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