#include "asterisk.h"#include "asterisk/_private.h"#include "asterisk/astobj2.h"#include "asterisk/utils.h"#include "asterisk/cli.h"
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. | |
| 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. | |
| 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 astobj2 * | INTERNAL_OBJ (void *user_data) |
| convert from a pointer _p to a user-defined object | |
| #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
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().
| 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.
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 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] |
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 755 of file astobj2.c.
References AO2_ITERATOR_DONTLOCK, ao2_lock(), AST_LIST_NEXT, AST_LIST_TRAVERSE, ao2_iterator::bucket, ao2_container::buckets, ao2_iterator::c, ao2_iterator::c_version, EXTERNAL_OBJ, 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().
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, 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 = 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(), and _moh_class_malloc().
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.
Referenced by _get_mohbyname().
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.
Referenced by _get_mohbyname().
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 }
| 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().
| 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.
| a | A pointer to the object we want to lock. |
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 | |||
| ) |
| void* ao2_object_get_lockaddr | ( | void * | obj | ) |
Return the lock address of an object.
| [in] | obj | A pointer to the object we want. |
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.
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).
| a | A pointer to the object we want to lock. |
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.
| a | A pointer to the object we want unlock. |
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 }
| AST_LIST_HEAD_NOLOCK | ( | bucket | , | |
| bucket_list | ||||
| ) |
| 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(), 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(), 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.
Definition at line 412 of file astobj2.c.
Referenced by __ao2_container_alloc().
| static struct astobj2* INTERNAL_OBJ | ( | void * | user_data | ) | [static, read] |
convert from a pointer _p to a user-defined object
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 }
1.6.1