#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/astobj2.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/paths.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_entry |
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 |
Enumerations | |
enum | ao2_callback_type { DEFAULT, WITH_DATA } |
Functions | |
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_data (struct ao2_container *c, const enum search_flags flags, ao2_callback_data_fn *cb_fn, void *arg, void *data) |
void * | __ao2_callback_data_debug (struct ao2_container *c, const enum search_flags flags, ao2_callback_data_fn *cb_fn, void *arg, void *data, char *tag, char *file, int line, const char *funcname) |
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_lock (void *user_data, const char *file, const char *func, int line, const char *var) |
Lock an object. | |
int | __ao2_ref (void *user_data, const int delta) |
int | __ao2_ref_debug (void *user_data, const int delta, const char *tag, const char *file, int line, const char *funcname) |
int | __ao2_trylock (void *user_data, const char *file, const char *func, int line, const char *var) |
Try locking-- (don't block if fail). | |
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) |
int | __ao2_unlock (void *user_data, const char *file, const char *func, int line, const char *var) |
Unlock an object. | |
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_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. | |
static void | astobj2_cleanup (void) |
int | astobj2_init (void) |
static int | cb_true (void *user_data, void *arg, int flags) |
special callback that matches all | |
static int | cb_true_data (void *user_data, void *arg, void *data, int flags) |
similar to cb_true, but is an ao2_callback_data_fn instead | |
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 void * | internal_ao2_alloc (size_t data_size, ao2_destructor_fn destructor_fn, const char *file, int line, const char *funcname) |
static void * | internal_ao2_callback (struct ao2_container *c, const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type, char *tag, char *file, int line, const char *funcname) |
static struct ao2_container * | internal_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 * | internal_ao2_container_alloc (struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn) |
static void * | internal_ao2_iterator_next (struct ao2_iterator *a, struct bucket_entry **q) |
static struct bucket_entry * | internal_ao2_link (struct ao2_container *c, void *user_data, const char *file, int line, const char *func) |
static int | internal_ao2_ref (void *user_data, const int delta) |
static struct astobj2 * | INTERNAL_OBJ (void *user_data) |
convert from a pointer _p to a user-defined object | |
Variables | |
static FILE * | ref_log |
#define AO2_MAGIC 0xa570b123 |
Definition at line 58 of file astobj2.c.
Referenced by internal_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 148 of file astobj2.c.
Referenced by internal_ao2_alloc(), internal_ao2_callback(), and internal_ao2_iterator_next().
#define N1 20 |
Referenced by ao2_bt().
enum ao2_callback_type |
void* __ao2_alloc | ( | size_t | data_size, | |
ao2_destructor_fn | destructor_fn | |||
) |
Definition at line 354 of file astobj2.c.
References internal_ao2_alloc().
Referenced by __ao2_container_alloc().
00355 { 00356 return internal_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 335 of file astobj2.c.
References ast_get_tid(), and internal_ao2_alloc().
Referenced by __ao2_container_alloc_debug(), __ast_channel_alloc_ap(), __ast_dummy_channel_alloc(), and _moh_class_malloc().
00337 { 00338 /* allocation */ 00339 void *obj; 00340 00341 if ((obj = internal_ao2_alloc(data_size, destructor_fn, file, line, funcname)) == NULL) { 00342 return NULL; 00343 } 00344 00345 if (ref_log) { 00346 fprintf(ref_log, "%p,+1,%d,%s,%d,%s,**constructor**,%s\n", obj, ast_get_tid(), file, line, funcname, tag); 00347 fflush(ref_log); 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 782 of file astobj2.c.
References DEFAULT, and internal_ao2_callback().
Referenced by __ao2_find(), __ao2_unlink(), and container_destruct().
00784 { 00785 return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL); 00786 }
void* __ao2_callback_data | ( | struct ao2_container * | c, | |
const enum search_flags | flags, | |||
ao2_callback_data_fn * | cb_fn, | |||
void * | arg, | |||
void * | data | |||
) |
Definition at line 796 of file astobj2.c.
References internal_ao2_callback(), and WITH_DATA.
00798 { 00799 return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL); 00800 }
void* __ao2_callback_data_debug | ( | struct ao2_container * | c, | |
const enum search_flags | flags, | |||
ao2_callback_data_fn * | cb_fn, | |||
void * | arg, | |||
void * | data, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 788 of file astobj2.c.
References internal_ao2_callback(), and WITH_DATA.
00792 { 00793 return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, funcname); 00794 }
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 774 of file astobj2.c.
References DEFAULT, and internal_ao2_callback().
Referenced by __ao2_find_debug(), __ao2_unlink_debug(), and container_destruct_debug().
00778 { 00779 return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, funcname); 00780 }
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_alloc(), container_destruct(), and internal_ao2_container_alloc().
00456 { 00457 /* XXX maybe consistency check on arguments ? */ 00458 /* compute the container size */ 00459 00460 const unsigned int num_buckets = hash_fn ? n_buckets : 1; 00461 size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket); 00462 struct ao2_container *c = __ao2_alloc(container_size, container_destruct); 00463 00464 return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn); 00465 }
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_alloc_debug(), container_destruct(), container_destruct_debug(), and internal_ao2_container_alloc().
00444 { 00445 /* XXX maybe consistency check on arguments ? */ 00446 /* compute the container size */ 00447 const unsigned int num_buckets = hash_fn ? n_buckets : 1; 00448 size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket); 00449 struct ao2_container *c = __ao2_alloc_debug(container_size, ref_debug ? container_destruct_debug : container_destruct, tag, file, line, funcname, ref_debug); 00450 00451 return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn); 00452 }
void* __ao2_find | ( | struct ao2_container * | c, | |
void * | arg, | |||
enum search_flags | flags | |||
) |
Definition at line 810 of file astobj2.c.
References __ao2_callback(), and ao2_container::cmp_fn.
Referenced by _get_mohbyname().
00811 { 00812 return __ao2_callback(c, flags, c->cmp_fn, arg); 00813 }
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 805 of file astobj2.c.
References __ao2_callback_debug(), and ao2_container::cmp_fn.
Referenced by _get_mohbyname().
00806 { 00807 return __ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname); 00808 }
void* __ao2_iterator_next | ( | struct ao2_iterator * | a | ) |
Definition at line 931 of file astobj2.c.
References __ao2_ref(), AO2_ITERATOR_DONTLOCK, ao2_unlock, ao2_iterator::c, ao2_iterator::flags, and internal_ao2_iterator_next().
00932 { 00933 struct bucket_entry *p = NULL; 00934 void *ret = NULL; 00935 00936 ret = internal_ao2_iterator_next(a, &p); 00937 00938 if (p) { 00939 /* inc refcount of returned object */ 00940 __ao2_ref(ret, 1); 00941 } 00942 00943 if (!(a->flags & AO2_ITERATOR_DONTLOCK)) 00944 ao2_unlock(a->c); 00945 00946 return ret; 00947 }
void* __ao2_iterator_next_debug | ( | struct ao2_iterator * | a, | |
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 913 of file astobj2.c.
References __ao2_ref_debug(), AO2_ITERATOR_DONTLOCK, ao2_unlock, ao2_iterator::c, ao2_iterator::flags, and internal_ao2_iterator_next().
00914 { 00915 struct bucket_entry *p; 00916 void *ret = NULL; 00917 00918 ret = internal_ao2_iterator_next(a, &p); 00919 00920 if (p) { 00921 /* inc refcount of returned object */ 00922 __ao2_ref_debug(ret, 1, tag, file, line, funcname); 00923 } 00924 00925 if (!(a->flags & AO2_ITERATOR_DONTLOCK)) 00926 ao2_unlock(a->c); 00927 00928 return ret; 00929 }
void* __ao2_link | ( | struct ao2_container * | c, | |
void * | user_data | |||
) |
Definition at line 531 of file astobj2.c.
References __ao2_ref(), ao2_unlock, and internal_ao2_link().
Referenced by internal_ao2_callback().
00532 { 00533 struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__); 00534 00535 if (p) { 00536 __ao2_ref(user_data, +1); 00537 ao2_unlock(c); 00538 } 00539 return p; 00540 }
void* __ao2_link_debug | ( | struct ao2_container * | c, | |
void * | user_data, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 520 of file astobj2.c.
References __ao2_ref_debug(), ao2_unlock, and internal_ao2_link().
Referenced by internal_ao2_callback().
00521 { 00522 struct bucket_entry *p = internal_ao2_link(c, user_data, file, line, funcname); 00523 00524 if (p) { 00525 __ao2_ref_debug(user_data, +1, tag, file, line, funcname); 00526 ao2_unlock(c); 00527 } 00528 return p; 00529 }
int __ao2_lock | ( | void * | a, | |
const char * | file, | |||
const char * | func, | |||
int | line, | |||
const char * | var | |||
) |
Lock an object.
a | A pointer to the object we want to lock. |
Definition at line 161 of file astobj2.c.
References __ast_pthread_mutex_lock(), ast_atomic_fetchadd_int(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00162 { 00163 struct astobj2 *p = INTERNAL_OBJ(user_data); 00164 00165 if (p == NULL) 00166 return -1; 00167 00168 #ifdef AO2_DEBUG 00169 ast_atomic_fetchadd_int(&ao2.total_locked, 1); 00170 #endif 00171 00172 return __ast_pthread_mutex_lock(file, line, func, var, &p->priv_data.lock); 00173 }
int __ao2_ref | ( | void * | user_data, | |
const int | delta | |||
) |
Definition at line 248 of file astobj2.c.
References internal_ao2_ref().
Referenced by __ao2_iterator_next(), __ao2_link(), cd_cb(), and internal_ao2_callback().
00249 { 00250 return internal_ao2_ref(user_data, delta); 00251 }
int __ao2_ref_debug | ( | void * | user_data, | |
const int | delta, | |||
const char * | tag, | |||
const char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 219 of file astobj2.c.
References ast_get_tid(), internal_ao2_ref(), and INTERNAL_OBJ().
Referenced by __ao2_iterator_next_debug(), __ao2_link_debug(), cd_cb_debug(), dialog_ref_debug(), dialog_unref_debug(), and internal_ao2_callback().
00220 { 00221 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00222 int old_refcount = -1; 00223 00224 if (obj) { 00225 old_refcount = internal_ao2_ref(user_data, delta); 00226 } 00227 00228 if (ref_log && user_data) { 00229 if (!obj) { 00230 /* Invalid object: Bad magic number. */ 00231 fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n", 00232 user_data, delta, ast_get_tid(), file, line, funcname, tag); 00233 fflush(ref_log); 00234 } else if (old_refcount + delta == 0) { 00235 fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**,%s\n", 00236 user_data, delta, ast_get_tid(), file, line, funcname, tag); 00237 fflush(ref_log); 00238 } else if (delta != 0) { 00239 fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data, (delta < 0 ? "" : "+"), 00240 delta, ast_get_tid(), file, line, funcname, old_refcount, tag); 00241 fflush(ref_log); 00242 } 00243 } 00244 00245 return old_refcount; 00246 }
int __ao2_trylock | ( | void * | a, | |
const char * | file, | |||
const char * | func, | |||
int | line, | |||
const char * | var | |||
) |
Try locking-- (don't block if fail).
a | A pointer to the object we want to lock. |
Definition at line 189 of file astobj2.c.
References __ast_pthread_mutex_trylock(), ast_atomic_fetchadd_int(), 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 ret = __ast_pthread_mutex_trylock(file, line, func, var, &p->priv_data.lock); 00197 00198 #ifdef AO2_DEBUG 00199 if (!ret) 00200 ast_atomic_fetchadd_int(&ao2.total_locked, 1); 00201 #endif 00202 return ret; 00203 }
void* __ao2_unlink | ( | struct ao2_container * | c, | |
void * | user_data | |||
) |
Definition at line 565 of file astobj2.c.
References __ao2_callback(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.
00566 { 00567 if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */ 00568 return NULL; 00569 00570 __ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data); 00571 00572 return NULL; 00573 }
void* __ao2_unlink_debug | ( | struct ao2_container * | c, | |
void * | user_data, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 554 of file astobj2.c.
References __ao2_callback_debug(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.
00556 { 00557 if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */ 00558 return NULL; 00559 00560 __ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname); 00561 00562 return NULL; 00563 }
int __ao2_unlock | ( | void * | a, | |
const char * | file, | |||
const char * | func, | |||
int | line, | |||
const char * | var | |||
) |
Unlock an object.
a | A pointer to the object we want unlock. |
Definition at line 175 of file astobj2.c.
References __ast_pthread_mutex_unlock(), ast_atomic_fetchadd_int(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00176 { 00177 struct astobj2 *p = INTERNAL_OBJ(user_data); 00178 00179 if (p == NULL) 00180 return -1; 00181 00182 #ifdef AO2_DEBUG 00183 ast_atomic_fetchadd_int(&ao2.total_locked, -1); 00184 #endif 00185 00186 return __ast_pthread_mutex_unlock(file, line, func, var, &p->priv_data.lock); 00187 }
void ao2_bt | ( | void | ) |
Definition at line 90 of file astobj2.c.
References ast_bt_get_symbols(), ast_std_free(), ast_verbose, and N1.
00091 { 00092 int c, i; 00093 #define N1 20 00094 void *addresses[N1]; 00095 char **strings; 00096 00097 c = backtrace(addresses, N1); 00098 strings = ast_bt_get_symbols(addresses,c); 00099 ast_verbose("backtrace returned: %d\n", c); 00100 for(i = 0; i < c; i++) { 00101 ast_verbose("%d: %p %s\n", i, addresses[i], strings[i]); 00102 } 00103 ast_std_free(strings); 00104 }
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 470 of file astobj2.c.
References ao2_container::elements.
Referenced by __ast_data_register(), __ast_manager_event_multichan(), __queues_show(), _sip_show_peers(), ast_active_channels(), ast_data_search_match(), ast_merge_contexts_and_delete(), ast_srtp_unprotect(), ast_tone_zone_count(), calc_metric(), cc_cli_output_status(), cleanup(), cli_fax_show_sessions(), cli_tps_report(), data_odbc_provider_handler(), data_provider_release(), data_provider_release_all(), do_monitor(), do_timing(), endelm(), get_unused_callno(), handle_cli_iax2_show_callno_limits(), handle_show_hint(), handle_show_hints(), hints_data_provider_get(), locals_show(), lock_broker(), match_filter(), meetme_data_provider_get(), member_add_to_queue(), pthread_timer_open(), queue_exec(), queue_function_qac(), queues_data_provider_get_helper(), sla_in_use(), try_calling(), and unload_module().
00471 { 00472 return c->elements; 00473 }
void ao2_iterator_destroy | ( | struct ao2_iterator * | i | ) |
Destroy a container iterator.
destroy an iterator
Definition at line 833 of file astobj2.c.
References AO2_ITERATOR_MALLOCD, ao2_ref, ast_free, ao2_iterator::c, and ao2_iterator::flags.
Referenced by __ast_data_search_cmp_structure(), __ast_manager_event_multichan(), __data_result_print_cli(), __iax2_show_peers(), __queues_show(), _sip_show_peers(), action_meetmelist(), alias_show(), ast_channel_iterator_destroy(), ast_data_iterator_end(), ast_data_search_match(), ast_merge_contexts_and_delete(), ast_srtp_unprotect(), ast_var_indications(), ast_var_indications_table(), astman_verify_session_readpermissions(), astman_verify_session_writepermissions(), authenticate(), authenticate_reply(), build_dialplan_useage_map(), calendar_query_exec(), check_access(), clear_queue(), clear_stats(), cli_console_active(), cli_fax_show_sessions(), cli_list_devices(), cli_tps_report(), compare_weight(), complete_core_id(), complete_core_show_hint(), complete_country(), complete_iax2_peers(), complete_iax2_unregister(), complete_queue(), complete_queue_remove_member(), complete_sip_peer(), complete_sip_registered_peer(), complete_sip_user(), complete_sipch(), complete_userno(), conf_queue_dtmf(), data_filter_find(), data_get_xml_add_child(), data_odbc_provider_handler(), data_provider_print_cli(), data_provider_release_all(), data_result_generate_node(), data_result_manager_output(), delete_profiles(), delete_routes(), delete_users(), destroy_pvts(), dialgroup_read(), do_parking_thread(), dump_queue_members(), extension_state_cb(), fax_session_tab_complete(), find_call(), find_queue_by_name_rt(), find_session(), find_session_by_nonce(), free_members(), get_member_status(), handle_cli_iax2_show_callno_limits(), handle_cli_iax2_show_users(), handle_cli_indication_show(), handle_cli_moh_show_classes(), handle_cli_moh_show_files(), handle_cli_odbc_show(), handle_cli_status(), handle_feature_show(), handle_parkedcalls(), handle_show_calendar(), handle_show_calendars(), handle_show_hint(), handle_show_hints(), handle_show_routes(), handle_showmanconn(), handle_statechange(), hints_data_provider_get(), iax2_getpeername(), iax2_getpeertrunk(), interface_exists(), kill_duplicate_offers(), local_devicestate(), locals_show(), manager_iax2_show_peer_list(), manager_optimize_away(), manager_parking_status(), manager_queues_status(), manager_queues_summary(), meetme_menu_admin_extended(), meetme_show_cmd(), moh_rescan_files(), num_available_members(), peers_data_provider_get(), poke_all_peers(), pp_each_user_helper(), prune_peers(), prune_users(), purge_sessions(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_queuememberpaused(), queue_function_queuememberstatus(), queues_data_provider_get(), queues_data_provider_get_helper(), 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(), sla_calc_station_delays(), sla_change_trunk_state(), sla_queue_event_conf(), sla_show_stations(), sla_show_trunks(), stop_streams(), tps_taskprocessor_tab_complete(), try_calling(), unload_module(), update_queue(), update_realtime_members(), and users_data_provider_get().
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 818 of file astobj2.c.
References ao2_ref, ao2_iterator::c, and ao2_iterator::flags.
Referenced by __ast_data_search_cmp_structure(), __ast_manager_event_multichan(), __data_result_print_cli(), __iax2_show_peers(), __queues_show(), action_meetmelist(), alias_show(), ast_channel_iterator_all_new(), ast_data_iterator_init(), ast_data_search_match(), ast_merge_contexts_and_delete(), ast_srtp_unprotect(), ast_tone_zone_iterator_init(), astman_verify_session_readpermissions(), astman_verify_session_writepermissions(), authenticate(), authenticate_reply(), build_dialplan_useage_map(), calendar_query_exec(), check_access(), clear_queue(), clear_stats(), cli_console_active(), cli_fax_show_sessions(), cli_list_devices(), cli_tps_report(), compare_weight(), complete_core_id(), complete_core_show_hint(), complete_country(), complete_iax2_peers(), complete_iax2_unregister(), complete_queue(), complete_queue_remove_member(), complete_sip_peer(), complete_sip_registered_peer(), complete_sip_user(), complete_sipch(), complete_userno(), conf_queue_dtmf(), data_filter_find(), data_get_xml_add_child(), data_odbc_provider_handler(), data_provider_print_cli(), data_provider_release_all(), data_result_generate_node(), data_result_manager_output(), delete_profiles(), delete_routes(), delete_users(), destroy_pvts(), dialgroup_read(), do_parking_thread(), dump_queue_members(), extension_state_cb(), fax_session_tab_complete(), find_queue_by_name_rt(), find_session(), find_session_by_nonce(), 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_cli_status(), handle_feature_show(), handle_parkedcalls(), handle_show_calendar(), handle_show_calendars(), handle_show_hint(), handle_show_hints(), handle_show_routes(), handle_showmanconn(), handle_statechange(), hints_data_provider_get(), iax2_getpeername(), iax2_getpeertrunk(), interface_exists(), internal_ao2_callback(), local_devicestate(), locals_show(), manager_iax2_show_peer_list(), manager_optimize_away(), manager_parking_status(), manager_queues_status(), manager_queues_summary(), meetme_menu_admin_extended(), meetme_show_cmd(), moh_rescan_files(), num_available_members(), peers_data_provider_get(), poke_all_peers(), pp_each_user_helper(), prune_peers(), prune_users(), purge_sessions(), queue_function_qac(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_function_queuememberpaused(), queue_function_queuememberstatus(), queues_data_provider_get(), queues_data_provider_get_helper(), 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(), sla_calc_station_delays(), sla_change_trunk_state(), sla_queue_event_conf(), sla_show_stations(), sla_show_trunks(), stop_streams(), tps_taskprocessor_tab_complete(), try_calling(), unload_module(), update_queue(), update_realtime_members(), and users_data_provider_get().
00819 { 00820 struct ao2_iterator a = { 00821 .c = c, 00822 .flags = flags 00823 }; 00824 00825 ao2_ref(c, +1); 00826 00827 return a; 00828 }
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 205 of file astobj2.c.
References INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00206 { 00207 struct astobj2 *p = INTERNAL_OBJ(obj); 00208 00209 if (p == NULL) 00210 return NULL; 00211 00212 return &p->priv_data.lock; 00213 }
static void astobj2_cleanup | ( | void | ) | [static] |
Definition at line 1137 of file astobj2.c.
References ARRAY_LEN, and ast_cli_unregister_multiple().
Referenced by astobj2_init().
01138 { 01139 #ifdef AO2_DEBUG 01140 ast_cli_unregister_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2)); 01141 #endif 01142 01143 #ifdef REF_DEBUG 01144 fclose(ref_log); 01145 ref_log = NULL; 01146 #endif 01147 }
int astobj2_init | ( | void | ) |
Provided by astobj2.c
Definition at line 1150 of file astobj2.c.
References ARRAY_LEN, ast_cli_register_multiple(), ast_config_AST_LOG_DIR, ast_log(), ast_register_atexit(), astobj2_cleanup(), and LOG_ERROR.
Referenced by main().
01151 { 01152 #ifdef REF_DEBUG 01153 char ref_filename[1024]; 01154 #endif 01155 01156 #ifdef REF_DEBUG 01157 snprintf(ref_filename, sizeof(ref_filename), "%s/refs", ast_config_AST_LOG_DIR); 01158 ref_log = fopen(ref_filename, "w"); 01159 if (!ref_log) { 01160 ast_log(LOG_ERROR, "Could not open ref debug log file: %s\n", ref_filename); 01161 } 01162 #endif 01163 01164 #ifdef AO2_DEBUG 01165 ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2)); 01166 #endif 01167 01168 ast_register_atexit(astobj2_cleanup); 01169 return 0; 01170 }
static int cb_true | ( | void * | user_data, | |
void * | arg, | |||
int | flags | |||
) | [static] |
special callback that matches all
Definition at line 578 of file astobj2.c.
References CMP_MATCH.
Referenced by internal_ao2_callback().
00579 { 00580 return CMP_MATCH; 00581 }
static int cb_true_data | ( | void * | user_data, | |
void * | arg, | |||
void * | data, | |||
int | flags | |||
) | [static] |
similar to cb_true, but is an ao2_callback_data_fn instead
Definition at line 586 of file astobj2.c.
References CMP_MATCH.
Referenced by internal_ao2_callback().
00587 { 00588 return CMP_MATCH; 00589 }
static int cd_cb | ( | void * | obj, | |
void * | arg, | |||
int | flag | |||
) | [static] |
Definition at line 952 of file astobj2.c.
References __ao2_ref().
Referenced by container_destruct().
00953 { 00954 __ao2_ref(obj, -1); 00955 return 0; 00956 }
static int cd_cb_debug | ( | void * | obj, | |
void * | arg, | |||
int | flag | |||
) | [static] |
Definition at line 958 of file astobj2.c.
References __ao2_ref_debug().
Referenced by container_destruct_debug().
00959 { 00960 __ao2_ref_debug(obj, -1, "deref object via container destroy", __FILE__, __LINE__, __PRETTY_FUNCTION__); 00961 return 0; 00962 }
static void container_destruct | ( | void * | c | ) | [static] |
Definition at line 964 of file astobj2.c.
References __ao2_callback(), ast_atomic_fetchadd_int(), ast_free, AST_LIST_REMOVE_HEAD, ao2_container::buckets, cd_cb(), bucket_entry::entry, ao2_container::n_buckets, and OBJ_UNLINK.
Referenced by __ao2_container_alloc(), and __ao2_container_alloc_debug().
00965 { 00966 struct ao2_container *c = _c; 00967 int i; 00968 00969 __ao2_callback(c, OBJ_UNLINK, cd_cb, NULL); 00970 00971 for (i = 0; i < c->n_buckets; i++) { 00972 struct bucket_entry *current; 00973 00974 while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) { 00975 ast_free(current); 00976 } 00977 } 00978 00979 #ifdef AO2_DEBUG 00980 ast_atomic_fetchadd_int(&ao2.total_containers, -1); 00981 #endif 00982 }
static void container_destruct_debug | ( | void * | c | ) | [static] |
Definition at line 984 of file astobj2.c.
References __ao2_callback_debug(), ast_atomic_fetchadd_int(), ast_free, AST_LIST_REMOVE_HEAD, ao2_container::buckets, cd_cb_debug(), bucket_entry::entry, ao2_container::n_buckets, and OBJ_UNLINK.
Referenced by __ao2_container_alloc_debug().
00985 { 00986 struct ao2_container *c = _c; 00987 int i; 00988 00989 __ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__); 00990 00991 for (i = 0; i < c->n_buckets; i++) { 00992 struct bucket_entry *current; 00993 00994 while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) { 00995 ast_free(current); 00996 } 00997 } 00998 00999 #ifdef AO2_DEBUG 01000 ast_atomic_fetchadd_int(&ao2.total_containers, -1); 01001 #endif 01002 }
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 internal_ao2_container_alloc().
static void* internal_ao2_alloc | ( | size_t | data_size, | |
ao2_destructor_fn | destructor_fn, | |||
const char * | file, | |||
int | line, | |||
const char * | funcname | |||
) | [static] |
Definition at line 302 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().
00303 { 00304 /* allocation */ 00305 struct astobj2 *obj; 00306 00307 if (data_size < sizeof(void *)) 00308 data_size = sizeof(void *); 00309 00310 #if defined(__AST_DEBUG_MALLOC) 00311 obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, funcname); 00312 #else 00313 obj = ast_calloc(1, sizeof(*obj) + data_size); 00314 #endif 00315 00316 if (obj == NULL) 00317 return NULL; 00318 00319 ast_mutex_init(&obj->priv_data.lock); 00320 obj->priv_data.magic = AO2_MAGIC; 00321 obj->priv_data.data_size = data_size; 00322 obj->priv_data.ref_counter = 1; 00323 obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */ 00324 00325 #ifdef AO2_DEBUG 00326 ast_atomic_fetchadd_int(&ao2.total_objects, 1); 00327 ast_atomic_fetchadd_int(&ao2.total_mem, data_size); 00328 ast_atomic_fetchadd_int(&ao2.total_refs, 1); 00329 #endif 00330 00331 /* return a pointer to the user data */ 00332 return EXTERNAL_OBJ(obj); 00333 }
static void * internal_ao2_callback | ( | struct ao2_container * | c, | |
const enum search_flags | flags, | |||
void * | cb_fn, | |||
void * | arg, | |||
void * | data, | |||
enum ao2_callback_type | type, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) | [static] |
Browse the container using different stategies accoding the flags.
Definition at line 599 of file astobj2.c.
References __ao2_link(), __ao2_link_debug(), __ao2_ref(), __ao2_ref_debug(), ao2_container_alloc, AO2_ITERATOR_DONTLOCK, ao2_iterator_init(), AO2_ITERATOR_MALLOCD, AO2_ITERATOR_UNLINK, ao2_lock, ao2_ref, ao2_unlock, ast_atomic_fetchadd_int(), ast_calloc, ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, bucket_entry::astobj, ao2_container::buckets, cb_true(), cb_true_data(), CMP_MATCH, CMP_STOP, ao2_container::elements, bucket_entry::entry, EXTERNAL_OBJ, ao2_container::hash_fn, INTERNAL_OBJ(), last, match(), ao2_container::n_buckets, OBJ_CONTINUE, OBJ_MULTIPLE, OBJ_NODATA, OBJ_POINTER, OBJ_UNLINK, ao2_container::version, and WITH_DATA.
Referenced by __ao2_callback(), __ao2_callback_data(), __ao2_callback_data_debug(), and __ao2_callback_debug().
00602 { 00603 int i, start, last; /* search boundaries */ 00604 void *ret = NULL; 00605 ao2_callback_fn *cb_default = NULL; 00606 ao2_callback_data_fn *cb_withdata = NULL; 00607 struct ao2_container *multi_container = NULL; 00608 struct ao2_iterator *multi_iterator = NULL; 00609 00610 if (INTERNAL_OBJ(c) == NULL) /* safety check on the argument */ 00611 return NULL; 00612 00613 /* 00614 * This logic is used so we can support OBJ_MULTIPLE with OBJ_NODATA 00615 * turned off. This if statement checks for the special condition 00616 * where multiple items may need to be returned. 00617 */ 00618 if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) { 00619 /* we need to return an ao2_iterator with the results, 00620 * as there could be more than one. the iterator will 00621 * hold the only reference to a container that has all the 00622 * matching objects linked into it, so when the iterator 00623 * is destroyed, the container will be automatically 00624 * destroyed as well. 00625 */ 00626 if (!(multi_container = ao2_container_alloc(1, NULL, NULL))) { 00627 return NULL; 00628 } 00629 if (!(multi_iterator = ast_calloc(1, sizeof(*multi_iterator)))) { 00630 ao2_ref(multi_container, -1); 00631 return NULL; 00632 } 00633 } 00634 00635 /* override the match function if necessary */ 00636 if (cb_fn == NULL) { /* if NULL, match everything */ 00637 if (type == WITH_DATA) { 00638 cb_withdata = cb_true_data; 00639 } else { 00640 cb_default = cb_true; 00641 } 00642 } else { 00643 /* We do this here to avoid the per object casting penalty (even though 00644 that is probably optimized away anyway). */ 00645 if (type == WITH_DATA) { 00646 cb_withdata = cb_fn; 00647 } else { 00648 cb_default = cb_fn; 00649 } 00650 } 00651 00652 /* 00653 * XXX this can be optimized. 00654 * If we have a hash function and lookup by pointer, 00655 * run the hash function. Otherwise, scan the whole container 00656 * (this only for the time being. We need to optimize this.) 00657 */ 00658 if ((flags & OBJ_POINTER)) /* we know hash can handle this case */ 00659 start = i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets; 00660 else /* don't know, let's scan all buckets */ 00661 start = i = -1; /* XXX this must be fixed later. */ 00662 00663 /* determine the search boundaries: i..last-1 */ 00664 if (i < 0) { 00665 start = i = 0; 00666 last = c->n_buckets; 00667 } else if ((flags & OBJ_CONTINUE)) { 00668 last = c->n_buckets; 00669 } else { 00670 last = i + 1; 00671 } 00672 00673 ao2_lock(c); /* avoid modifications to the content */ 00674 00675 for (; i < last ; i++) { 00676 /* scan the list with prev-cur pointers */ 00677 struct bucket_entry *cur; 00678 00679 AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) { 00680 int match = (CMP_MATCH | CMP_STOP); 00681 00682 if (type == WITH_DATA) { 00683 match &= cb_withdata(EXTERNAL_OBJ(cur->astobj), arg, data, flags); 00684 } else { 00685 match &= cb_default(EXTERNAL_OBJ(cur->astobj), arg, flags); 00686 } 00687 00688 /* we found the object, performing operations according flags */ 00689 if (match == 0) { /* no match, no stop, continue */ 00690 continue; 00691 } else if (match == CMP_STOP) { /* no match but stop, we are done */ 00692 i = last; 00693 break; 00694 } 00695 00696 /* we have a match (CMP_MATCH) here */ 00697 if (!(flags & OBJ_NODATA)) { /* if must return the object, record the value */ 00698 /* it is important to handle this case before the unlink */ 00699 ret = EXTERNAL_OBJ(cur->astobj); 00700 if (!(flags & (OBJ_UNLINK | OBJ_MULTIPLE))) { 00701 if (tag) 00702 __ao2_ref_debug(ret, 1, tag, file, line, funcname); 00703 else 00704 __ao2_ref(ret, 1); 00705 } 00706 } 00707 00708 /* If we are in OBJ_MULTIPLE mode and OBJ_NODATE is off, 00709 * link the object into the container that will hold the results. 00710 */ 00711 if (ret && (multi_container != NULL)) { 00712 if (tag) { 00713 __ao2_link_debug(multi_container, ret, tag, file, line, funcname); 00714 } else { 00715 __ao2_link(multi_container, ret); 00716 } 00717 ret = NULL; 00718 } 00719 00720 if (flags & OBJ_UNLINK) { /* must unlink */ 00721 /* we are going to modify the container, so update version */ 00722 ast_atomic_fetchadd_int(&c->version, 1); 00723 AST_LIST_REMOVE_CURRENT(entry); 00724 /* update number of elements */ 00725 ast_atomic_fetchadd_int(&c->elements, -1); 00726 00727 /* - When unlinking and not returning the result, (OBJ_NODATA), the ref from the container 00728 * must be decremented. 00729 * - When unlinking with OBJ_MULTIPLE the ref from the original container 00730 * must be decremented regardless if OBJ_NODATA is used. This is because the result is 00731 * returned in a new container that already holds its own ref for the object. If the ref 00732 * from the original container is not accounted for here a memory leak occurs. */ 00733 if (flags & (OBJ_NODATA | OBJ_MULTIPLE)) { 00734 if (tag) 00735 __ao2_ref_debug(EXTERNAL_OBJ(cur->astobj), -1, tag, file, line, funcname); 00736 else 00737 __ao2_ref(EXTERNAL_OBJ(cur->astobj), -1); 00738 } 00739 ast_free(cur); /* free the link record */ 00740 } 00741 00742 if ((match & CMP_STOP) || !(flags & OBJ_MULTIPLE)) { 00743 /* We found our only (or last) match, so force an exit from 00744 the outside loop. */ 00745 i = last; 00746 break; 00747 } 00748 } 00749 AST_LIST_TRAVERSE_SAFE_END; 00750 00751 if (ret) { 00752 break; 00753 } 00754 00755 if (i == c->n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) { 00756 /* Move to the beginning to ensure we check every bucket */ 00757 i = -1; 00758 last = start; 00759 } 00760 } 00761 ao2_unlock(c); 00762 00763 /* if multi_container was created, we are returning multiple objects */ 00764 if (multi_container != NULL) { 00765 *multi_iterator = ao2_iterator_init(multi_container, 00766 AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK | AO2_ITERATOR_MALLOCD); 00767 ao2_ref(multi_container, -1); 00768 return multi_iterator; 00769 } else { 00770 return ret; 00771 } 00772 }
static struct ao2_container* internal_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 = hash_fn ? n_buckets : 1; 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* internal_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 * internal_ao2_iterator_next | ( | struct ao2_iterator * | a, | |
struct bucket_entry ** | q | |||
) | [static] |
Definition at line 846 of file astobj2.c.
References AO2_ITERATOR_DONTLOCK, AO2_ITERATOR_UNLINK, ao2_lock, ast_atomic_fetchadd_int(), ast_free, AST_LIST_NEXT, AST_LIST_REMOVE, AST_LIST_TRAVERSE, bucket_entry::astobj, ao2_iterator::bucket, ao2_container::buckets, ao2_iterator::c, ao2_iterator::c_version, ao2_container::elements, bucket_entry::entry, EXTERNAL_OBJ, ao2_iterator::flags, INTERNAL_OBJ(), ao2_container::n_buckets, ao2_iterator::obj, bucket_entry::version, ao2_iterator::version, and ao2_container::version.
Referenced by __ao2_iterator_next(), and __ao2_iterator_next_debug().
00847 { 00848 int lim; 00849 struct bucket_entry *p = NULL; 00850 void *ret = NULL; 00851 00852 *q = NULL; 00853 00854 if (INTERNAL_OBJ(a->c) == NULL) 00855 return NULL; 00856 00857 if (!(a->flags & AO2_ITERATOR_DONTLOCK)) 00858 ao2_lock(a->c); 00859 00860 /* optimization. If the container is unchanged and 00861 * we have a pointer, try follow it 00862 */ 00863 if (a->c->version == a->c_version && (p = a->obj)) { 00864 if ((p = AST_LIST_NEXT(p, entry))) 00865 goto found; 00866 /* nope, start from the next bucket */ 00867 a->bucket++; 00868 a->version = 0; 00869 a->obj = NULL; 00870 } 00871 00872 lim = a->c->n_buckets; 00873 00874 /* Browse the buckets array, moving to the next 00875 * buckets if we don't find the entry in the current one. 00876 * Stop when we find an element with version number greater 00877 * than the current one (we reset the version to 0 when we 00878 * switch buckets). 00879 */ 00880 for (; a->bucket < lim; a->bucket++, a->version = 0) { 00881 /* scan the current bucket */ 00882 AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) { 00883 if (p->version > a->version) 00884 goto found; 00885 } 00886 } 00887 00888 found: 00889 if (p) { 00890 ret = EXTERNAL_OBJ(p->astobj); 00891 if (a->flags & AO2_ITERATOR_UNLINK) { 00892 /* we are going to modify the container, so update version */ 00893 ast_atomic_fetchadd_int(&a->c->version, 1); 00894 AST_LIST_REMOVE(&a->c->buckets[a->bucket], p, entry); 00895 /* update number of elements */ 00896 ast_atomic_fetchadd_int(&a->c->elements, -1); 00897 a->version = 0; 00898 a->obj = NULL; 00899 a->c_version = a->c->version; 00900 ast_free(p); 00901 } else { 00902 a->version = p->version; 00903 a->obj = p; 00904 a->c_version = a->c->version; 00905 /* inc refcount of returned object */ 00906 *q = p; 00907 } 00908 } 00909 00910 return ret; 00911 }
static struct bucket_entry * internal_ao2_link | ( | struct ao2_container * | c, | |
void * | user_data, | |||
const char * | file, | |||
int | line, | |||
const char * | func | |||
) | [static, read] |
Definition at line 490 of file astobj2.c.
References ao2_lock, ast_atomic_fetchadd_int(), ast_calloc, AST_LIST_INSERT_TAIL, bucket_entry::astobj, INTERNAL_OBJ(), OBJ_POINTER, and bucket_entry::version.
Referenced by __ao2_link(), and __ao2_link_debug().
00491 { 00492 int i; 00493 /* create a new list entry */ 00494 struct bucket_entry *p; 00495 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00496 00497 if (obj == NULL) 00498 return NULL; 00499 00500 if (INTERNAL_OBJ(c) == NULL) 00501 return NULL; 00502 00503 p = ast_calloc(1, sizeof(*p)); 00504 if (!p) 00505 return NULL; 00506 00507 i = abs(c->hash_fn(user_data, OBJ_POINTER)); 00508 00509 ao2_lock(c); 00510 i %= c->n_buckets; 00511 p->astobj = obj; 00512 p->version = ast_atomic_fetchadd_int(&c->version, 1); 00513 AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry); 00514 ast_atomic_fetchadd_int(&c->elements, 1); 00515 00516 /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */ 00517 return p; 00518 }
static int internal_ao2_ref | ( | void * | user_data, | |
const int | delta | |||
) | [static] |
Definition at line 253 of file astobj2.c.
References ast_atomic_fetchadd_int(), ast_free, ast_log(), ast_mutex_destroy, __priv_data::data_size, __priv_data::destructor_fn, INTERNAL_OBJ(), __priv_data::lock, LOG_ERROR, astobj2::priv_data, and __priv_data::ref_counter.
Referenced by __ao2_ref(), and __ao2_ref_debug().
00254 { 00255 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00256 int current_value; 00257 int ret; 00258 00259 if (obj == NULL) 00260 return -1; 00261 00262 /* if delta is 0, just return the refcount */ 00263 if (delta == 0) 00264 return (obj->priv_data.ref_counter); 00265 00266 /* we modify with an atomic operation the reference counter */ 00267 ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta); 00268 current_value = ret + delta; 00269 00270 #ifdef AO2_DEBUG 00271 ast_atomic_fetchadd_int(&ao2.total_refs, delta); 00272 #endif 00273 00274 /* this case must never happen */ 00275 if (current_value < 0) 00276 ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data); 00277 00278 if (current_value <= 0) { /* last reference, destroy the object */ 00279 if (obj->priv_data.destructor_fn != NULL) { 00280 obj->priv_data.destructor_fn(user_data); 00281 } 00282 00283 ast_mutex_destroy(&obj->priv_data.lock); 00284 #ifdef AO2_DEBUG 00285 ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size); 00286 ast_atomic_fetchadd_int(&ao2.total_objects, -1); 00287 #endif 00288 /* for safety, zero-out the astobj2 header and also the 00289 * first word of the user-data, which we make sure is always 00290 * allocated. */ 00291 memset(obj, '\0', sizeof(struct astobj2 *) + sizeof(void *) ); 00292 ast_free(obj); 00293 } 00294 00295 return ret; 00296 }
static struct astobj2* INTERNAL_OBJ | ( | void * | user_data | ) | [static, read] |
convert from a pointer _p to a user-defined object
Definition at line 112 of file astobj2.c.
References AO2_MAGIC, ast_assert, ast_log(), LOG_ERROR, __priv_data::magic, and astobj2::priv_data.
Referenced by __ao2_lock(), __ao2_ref_debug(), __ao2_trylock(), __ao2_unlink(), __ao2_unlink_debug(), __ao2_unlock(), ao2_object_get_lockaddr(), internal_ao2_callback(), internal_ao2_iterator_next(), internal_ao2_link(), and internal_ao2_ref().
00113 { 00114 struct astobj2 *p; 00115 00116 if (!user_data) { 00117 ast_log(LOG_ERROR, "user_data is NULL\n"); 00118 return NULL; 00119 } 00120 00121 p = (struct astobj2 *) ((char *) user_data - sizeof(*p)); 00122 if (AO2_MAGIC != p->priv_data.magic) { 00123 if (p->priv_data.magic) { 00124 ast_log(LOG_ERROR, "bad magic number 0x%x for object %p\n", 00125 p->priv_data.magic, user_data); 00126 } else { 00127 ast_log(LOG_ERROR, 00128 "bad magic number for object %p. Object is likely destroyed.\n", 00129 user_data); 00130 } 00131 ast_assert(0); 00132 return NULL; 00133 } 00134 00135 return p; 00136 }