#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/astobj2.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include <execinfo.h>
Go to the source code of this file.
Data Structures | |
struct | __priv_data |
struct | ao2_container |
struct | astobj2 |
struct | bucket |
struct | bucket_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 |
#define | REF_FILE "/tmp/refs" |
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) |
ao2_container * | __ao2_container_alloc (const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn) |
ao2_container * | __ao2_container_alloc_debug (const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn, char *tag, char *file, int line, const char *funcname, 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, char *tag, 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. | |
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. | |
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 |
#define AO2_MAGIC 0xa570b123 |
#define EXTERNAL_OBJ | ( | _p | ) | ((_p) == NULL ? NULL : (_p)->user_data) |
convert from a pointer _p to an astobj2 object
Definition at line 138 of file astobj2.c.
Referenced by internal_ao2_alloc(), and internal_ao2_callback().
#define N1 20 |
Referenced by ao2_bt().
#define REF_FILE "/tmp/refs" |
enum ao2_callback_type |
void* __ao2_alloc | ( | size_t | data_size, | |
ao2_destructor_fn | destructor_fn | |||
) |
Definition at line 342 of file astobj2.c.
References internal_ao2_alloc().
Referenced by __ao2_container_alloc().
00343 { 00344 return internal_ao2_alloc(data_size, destructor_fn, __FILE__, __LINE__, __FUNCTION__); 00345 }
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 322 of file astobj2.c.
References internal_ao2_alloc(), and REF_FILE.
Referenced by __ao2_container_alloc_debug(), __ast_channel_alloc_ap(), _moh_class_malloc(), and ast_dummy_channel_alloc().
00324 { 00325 /* allocation */ 00326 void *obj; 00327 FILE *refo; 00328 00329 if ((obj = internal_ao2_alloc(data_size, destructor_fn, file, line, funcname)) == NULL) { 00330 return NULL; 00331 } 00332 00333 if (ref_debug && (refo = fopen(REF_FILE, "a"))) { 00334 fprintf(refo, "%p =1 %s:%d:%s (%s)\n", obj, file, line, funcname, tag); 00335 fclose(refo); 00336 } 00337 00338 /* return a pointer to the user data */ 00339 return obj; 00340 }
void* __ao2_callback | ( | struct ao2_container * | c, | |
const enum search_flags | flags, | |||
ao2_callback_fn * | cb_fn, | |||
void * | arg | |||
) |
Definition at line 770 of file astobj2.c.
References ao2_iterator::c, DEFAULT, and internal_ao2_callback().
Referenced by __ao2_find(), __ao2_unlink(), and container_destruct().
00772 { 00773 return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL); 00774 }
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 784 of file astobj2.c.
References ao2_iterator::c, internal_ao2_callback(), and WITH_DATA.
00786 { 00787 return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL); 00788 }
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 776 of file astobj2.c.
References ao2_iterator::c, internal_ao2_callback(), and WITH_DATA.
00780 { 00781 return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, funcname); 00782 }
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 762 of file astobj2.c.
References ao2_iterator::c, DEFAULT, and internal_ao2_callback().
Referenced by __ao2_find_debug(), __ao2_unlink_debug(), and container_destruct_debug().
00766 { 00767 return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, funcname); 00768 }
struct ao2_container* __ao2_container_alloc | ( | const unsigned int | n_buckets, | |
ao2_hash_fn * | hash_fn, | |||
ao2_callback_fn * | cmp_fn | |||
) |
Definition at line 442 of file astobj2.c.
References __ao2_alloc(), container_destruct(), and internal_ao2_container_alloc().
Referenced by internal_ao2_callback().
00444 { 00445 /* XXX maybe consistency check on arguments ? */ 00446 /* compute the container size */ 00447 00448 const unsigned int num_buckets = hash_fn ? n_buckets : 1; 00449 size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket); 00450 struct ao2_container *c = __ao2_alloc(container_size, container_destruct); 00451 00452 return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn); 00453 }
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 | |||
) |
Definition at line 429 of file astobj2.c.
References __ao2_alloc_debug(), container_destruct_debug(), and internal_ao2_container_alloc().
00432 { 00433 /* XXX maybe consistency check on arguments ? */ 00434 /* compute the container size */ 00435 const unsigned int num_buckets = hash_fn ? n_buckets : 1; 00436 size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket); 00437 struct ao2_container *c = __ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname, ref_debug); 00438 00439 return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn); 00440 }
void* __ao2_find | ( | struct ao2_container * | c, | |
void * | arg, | |||
enum search_flags | flags | |||
) |
Definition at line 798 of file astobj2.c.
References __ao2_callback(), ao2_iterator::c, and ao2_container::cmp_fn.
Referenced by _get_mohbyname().
00799 { 00800 return __ao2_callback(c, flags, c->cmp_fn, arg); 00801 }
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 793 of file astobj2.c.
References __ao2_callback_debug(), ao2_iterator::c, and ao2_container::cmp_fn.
Referenced by _get_mohbyname().
00794 { 00795 return __ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname); 00796 }
void* __ao2_iterator_next | ( | struct ao2_iterator * | a | ) |
Definition at line 919 of file astobj2.c.
References __ao2_ref(), AO2_ITERATOR_DONTLOCK, ao2_unlock, ao2_iterator::c, ao2_iterator::flags, and internal_ao2_iterator_next().
00920 { 00921 struct bucket_entry *p = NULL; 00922 void *ret = NULL; 00923 00924 ret = internal_ao2_iterator_next(a, &p); 00925 00926 if (p) { 00927 /* inc refcount of returned object */ 00928 __ao2_ref(ret, 1); 00929 } 00930 00931 if (!(a->flags & AO2_ITERATOR_DONTLOCK)) 00932 ao2_unlock(a->c); 00933 00934 return ret; 00935 }
void* __ao2_iterator_next_debug | ( | struct ao2_iterator * | a, | |
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 901 of file astobj2.c.
References __ao2_ref_debug(), AO2_ITERATOR_DONTLOCK, ao2_unlock, ao2_iterator::c, ao2_iterator::flags, and internal_ao2_iterator_next().
00902 { 00903 struct bucket_entry *p; 00904 void *ret = NULL; 00905 00906 ret = internal_ao2_iterator_next(a, &p); 00907 00908 if (p) { 00909 /* inc refcount of returned object */ 00910 __ao2_ref_debug(ret, 1, tag, file, line, funcname); 00911 } 00912 00913 if (!(a->flags & AO2_ITERATOR_DONTLOCK)) 00914 ao2_unlock(a->c); 00915 00916 return ret; 00917 }
void* __ao2_link | ( | struct ao2_container * | c, | |
void * | user_data | |||
) |
Definition at line 519 of file astobj2.c.
References __ao2_ref(), ao2_unlock, and internal_ao2_link().
Referenced by internal_ao2_callback().
00520 { 00521 struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__); 00522 00523 if (p) { 00524 __ao2_ref(user_data, +1); 00525 ao2_unlock(c); 00526 } 00527 return p; 00528 }
void* __ao2_link_debug | ( | struct ao2_container * | c, | |
void * | user_data, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 508 of file astobj2.c.
References __ao2_ref_debug(), ao2_unlock, and internal_ao2_link().
Referenced by internal_ao2_callback().
00509 { 00510 struct bucket_entry *p = internal_ao2_link(c, user_data, file, line, funcname); 00511 00512 if (p) { 00513 __ao2_ref_debug(user_data, +1, tag, file, line, funcname); 00514 ao2_unlock(c); 00515 } 00516 return p; 00517 }
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 151 of file astobj2.c.
References __ast_pthread_mutex_lock(), ast_atomic_fetchadd_int(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00152 { 00153 struct astobj2 *p = INTERNAL_OBJ(user_data); 00154 00155 if (p == NULL) 00156 return -1; 00157 00158 #ifdef AO2_DEBUG 00159 ast_atomic_fetchadd_int(&ao2.total_locked, 1); 00160 #endif 00161 00162 return __ast_pthread_mutex_lock(file, line, func, var, &p->priv_data.lock); 00163 }
int __ao2_ref | ( | void * | user_data, | |
const int | delta | |||
) |
Definition at line 235 of file astobj2.c.
References internal_ao2_ref().
Referenced by __ao2_iterator_next(), __ao2_link(), cd_cb(), and internal_ao2_callback().
00236 { 00237 return internal_ao2_ref(user_data, delta); 00238 }
int __ao2_ref_debug | ( | void * | user_data, | |
const int | delta, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 210 of file astobj2.c.
References __priv_data::destructor_fn, internal_ao2_ref(), INTERNAL_OBJ(), astobj2::priv_data, __priv_data::ref_counter, and REF_FILE.
Referenced by __ao2_iterator_next_debug(), __ao2_link_debug(), cd_cb_debug(), dialog_ref_debug(), dialog_unref_debug(), and internal_ao2_callback().
00211 { 00212 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00213 00214 if (obj == NULL) 00215 return -1; 00216 00217 if (delta != 0) { 00218 FILE *refo = fopen(REF_FILE, "a"); 00219 if (refo) { 00220 fprintf(refo, "%p %s%d %s:%d:%s (%s) [@%d]\n", user_data, (delta < 0 ? "" : "+"), 00221 delta, file, line, funcname, tag, obj ? obj->priv_data.ref_counter : -1); 00222 fclose(refo); 00223 } 00224 } 00225 if (obj->priv_data.ref_counter + delta == 0 && obj->priv_data.destructor_fn != NULL) { /* this isn't protected with lock; just for o/p */ 00226 FILE *refo = fopen(REF_FILE, "a"); 00227 if (refo) { 00228 fprintf(refo, "%p **call destructor** %s:%d:%s (%s)\n", user_data, file, line, funcname, tag); 00229 fclose(refo); 00230 } 00231 } 00232 return internal_ao2_ref(user_data, delta); 00233 }
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 179 of file astobj2.c.
References __ast_pthread_mutex_trylock(), ast_atomic_fetchadd_int(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00180 { 00181 struct astobj2 *p = INTERNAL_OBJ(user_data); 00182 int ret; 00183 00184 if (p == NULL) 00185 return -1; 00186 ret = __ast_pthread_mutex_trylock(file, line, func, var, &p->priv_data.lock); 00187 00188 #ifdef AO2_DEBUG 00189 if (!ret) 00190 ast_atomic_fetchadd_int(&ao2.total_locked, 1); 00191 #endif 00192 return ret; 00193 }
void* __ao2_unlink | ( | struct ao2_container * | c, | |
void * | user_data | |||
) |
Definition at line 553 of file astobj2.c.
References __ao2_callback(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.
00554 { 00555 if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */ 00556 return NULL; 00557 00558 __ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data); 00559 00560 return NULL; 00561 }
void* __ao2_unlink_debug | ( | struct ao2_container * | c, | |
void * | user_data, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 542 of file astobj2.c.
References __ao2_callback_debug(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.
00544 { 00545 if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */ 00546 return NULL; 00547 00548 __ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname); 00549 00550 return NULL; 00551 }
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 165 of file astobj2.c.
References __ast_pthread_mutex_unlock(), ast_atomic_fetchadd_int(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00166 { 00167 struct astobj2 *p = INTERNAL_OBJ(user_data); 00168 00169 if (p == NULL) 00170 return -1; 00171 00172 #ifdef AO2_DEBUG 00173 ast_atomic_fetchadd_int(&ao2.total_locked, -1); 00174 #endif 00175 00176 return __ast_pthread_mutex_unlock(file, line, func, var, &p->priv_data.lock); 00177 }
void ao2_bt | ( | void | ) |
Definition at line 88 of file astobj2.c.
References ast_bt_get_symbols(), ast_verbose, free, and N1.
00089 { 00090 int c, i; 00091 #define N1 20 00092 void *addresses[N1]; 00093 char **strings; 00094 00095 c = backtrace(addresses, N1); 00096 strings = ast_bt_get_symbols(addresses,c); 00097 ast_verbose("backtrace returned: %d\n", c); 00098 for(i = 0; i < c; i++) { 00099 ast_verbose("%d: %p %s\n", i, addresses[i], strings[i]); 00100 } 00101 free(strings); 00102 }
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 458 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_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(), pthread_timer_open(), queue_exec(), queue_function_qac(), queues_data_provider_get_helper(), try_calling(), and unload_module().
00459 { 00460 return c->elements; 00461 }
void ao2_iterator_destroy | ( | struct ao2_iterator * | i | ) |
Destroy a container iterator.
destroy an iterator
Definition at line 821 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_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_meetmecmd(), complete_queue(), complete_queue_remove_member(), complete_sip_peer(), complete_sip_registered_peer(), complete_sip_user(), complete_sipch(), conf_queue_dtmf(), conf_run(), 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_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_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(), 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(), 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(), stop_streams(), tps_taskprocessor_tab_complete(), unload_module(), update_queue(), update_realtime_members(), and users_data_provider_get().
00822 { 00823 ao2_ref(i->c, -1); 00824 if (i->flags & AO2_ITERATOR_MALLOCD) { 00825 ast_free(i); 00826 } else { 00827 i->c = NULL; 00828 } 00829 }
struct ao2_iterator ao2_iterator_init | ( | struct ao2_container * | c, | |
int | flags | |||
) |
Create an iterator for a container.
initialize an iterator so we start from the first object
Definition at line 806 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_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_meetmecmd(), complete_queue(), complete_queue_remove_member(), complete_sip_peer(), complete_sip_registered_peer(), complete_sip_user(), complete_sipch(), conf_queue_dtmf(), conf_run(), 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_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_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(), 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(), 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(), stop_streams(), tps_taskprocessor_tab_complete(), unload_module(), update_queue(), update_realtime_members(), and users_data_provider_get().
00807 { 00808 struct ao2_iterator a = { 00809 .c = c, 00810 .flags = flags 00811 }; 00812 00813 ao2_ref(c, +1); 00814 00815 return a; 00816 }
int ao2_match_by_addr | ( | void * | user_data, | |
void * | arg, | |||
int | flags | |||
) |
void* ao2_object_get_lockaddr | ( | void * | obj | ) |
Return the lock address of an object.
[in] | obj | A pointer to the object we want. |
Definition at line 195 of file astobj2.c.
References INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00196 { 00197 struct astobj2 *p = INTERNAL_OBJ(obj); 00198 00199 if (p == NULL) 00200 return NULL; 00201 00202 return &p->priv_data.lock; 00203 }
int astobj2_init | ( | void | ) |
Provided by astobj2.c
Definition at line 1125 of file astobj2.c.
References ARRAY_LEN, and ast_cli_register_multiple().
Referenced by main().
01126 { 01127 #ifdef AO2_DEBUG 01128 ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2)); 01129 #endif 01130 01131 return 0; 01132 }
static int cb_true | ( | void * | user_data, | |
void * | arg, | |||
int | flags | |||
) | [static] |
special callback that matches all
Definition at line 566 of file astobj2.c.
References CMP_MATCH.
Referenced by internal_ao2_callback().
00567 { 00568 return CMP_MATCH; 00569 }
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 574 of file astobj2.c.
References CMP_MATCH.
Referenced by internal_ao2_callback().
00575 { 00576 return CMP_MATCH; 00577 }
static int cd_cb | ( | void * | obj, | |
void * | arg, | |||
int | flag | |||
) | [static] |
Definition at line 940 of file astobj2.c.
References __ao2_ref().
Referenced by container_destruct().
00941 { 00942 __ao2_ref(obj, -1); 00943 return 0; 00944 }
static int cd_cb_debug | ( | void * | obj, | |
void * | arg, | |||
int | flag | |||
) | [static] |
Definition at line 946 of file astobj2.c.
References __ao2_ref_debug().
Referenced by container_destruct_debug().
00947 { 00948 __ao2_ref_debug(obj, -1, "deref object via container destroy", __FILE__, __LINE__, __PRETTY_FUNCTION__); 00949 return 0; 00950 }
static void container_destruct | ( | void * | c | ) | [static] |
Definition at line 952 of file astobj2.c.
References __ao2_callback(), ast_free, AST_LIST_REMOVE_HEAD, ao2_container::buckets, cd_cb(), ao2_container::n_buckets, and OBJ_UNLINK.
Referenced by __ao2_container_alloc().
00953 { 00954 struct ao2_container *c = _c; 00955 int i; 00956 00957 __ao2_callback(c, OBJ_UNLINK, cd_cb, NULL); 00958 00959 for (i = 0; i < c->n_buckets; i++) { 00960 struct bucket_entry *current; 00961 00962 while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) { 00963 ast_free(current); 00964 } 00965 } 00966 00967 #ifdef AO2_DEBUG 00968 ast_atomic_fetchadd_int(&ao2.total_containers, -1); 00969 #endif 00970 }
static void container_destruct_debug | ( | void * | c | ) | [static] |
Definition at line 972 of file astobj2.c.
References __ao2_callback_debug(), ast_free, AST_LIST_REMOVE_HEAD, ao2_container::buckets, cd_cb_debug(), ao2_container::n_buckets, and OBJ_UNLINK.
Referenced by __ao2_container_alloc_debug().
00973 { 00974 struct ao2_container *c = _c; 00975 int i; 00976 00977 __ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__); 00978 00979 for (i = 0; i < c->n_buckets; i++) { 00980 struct bucket_entry *current; 00981 00982 while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) { 00983 ast_free(current); 00984 } 00985 } 00986 00987 #ifdef AO2_DEBUG 00988 ast_atomic_fetchadd_int(&ao2.total_containers, -1); 00989 #endif 00990 }
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 400 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 289 of file astobj2.c.
References __ast_calloc(), AO2_MAGIC, ast_atomic_fetchadd_int(), ast_calloc, ast_mutex_init, and EXTERNAL_OBJ.
Referenced by __ao2_alloc(), and __ao2_alloc_debug().
00290 { 00291 /* allocation */ 00292 struct astobj2 *obj; 00293 00294 if (data_size < sizeof(void *)) 00295 data_size = sizeof(void *); 00296 00297 #if defined(__AST_DEBUG_MALLOC) 00298 obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, funcname); 00299 #else 00300 obj = ast_calloc(1, sizeof(*obj) + data_size); 00301 #endif 00302 00303 if (obj == NULL) 00304 return NULL; 00305 00306 ast_mutex_init(&obj->priv_data.lock); 00307 obj->priv_data.magic = AO2_MAGIC; 00308 obj->priv_data.data_size = data_size; 00309 obj->priv_data.ref_counter = 1; 00310 obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */ 00311 00312 #ifdef AO2_DEBUG 00313 ast_atomic_fetchadd_int(&ao2.total_objects, 1); 00314 ast_atomic_fetchadd_int(&ao2.total_mem, data_size); 00315 ast_atomic_fetchadd_int(&ao2.total_refs, 1); 00316 #endif 00317 00318 /* return a pointer to the user data */ 00319 return EXTERNAL_OBJ(obj); 00320 }
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 587 of file astobj2.c.
References __ao2_container_alloc(), __ao2_link(), __ao2_link_debug(), __ao2_ref(), __ao2_ref_debug(), 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, ao2_container::buckets, ao2_iterator::c, 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().
00590 { 00591 int i, start, last; /* search boundaries */ 00592 void *ret = NULL; 00593 ao2_callback_fn *cb_default = NULL; 00594 ao2_callback_data_fn *cb_withdata = NULL; 00595 struct ao2_container *multi_container = NULL; 00596 struct ao2_iterator *multi_iterator = NULL; 00597 00598 if (INTERNAL_OBJ(c) == NULL) /* safety check on the argument */ 00599 return NULL; 00600 00601 /* 00602 * This logic is used so we can support OBJ_MULTIPLE with OBJ_NODATA 00603 * turned off. This if statement checks for the special condition 00604 * where multiple items may need to be returned. 00605 */ 00606 if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) { 00607 /* we need to return an ao2_iterator with the results, 00608 * as there could be more than one. the iterator will 00609 * hold the only reference to a container that has all the 00610 * matching objects linked into it, so when the iterator 00611 * is destroyed, the container will be automatically 00612 * destroyed as well. 00613 */ 00614 if (!(multi_container = __ao2_container_alloc(1, NULL, NULL))) { 00615 return NULL; 00616 } 00617 if (!(multi_iterator = ast_calloc(1, sizeof(*multi_iterator)))) { 00618 ao2_ref(multi_container, -1); 00619 return NULL; 00620 } 00621 } 00622 00623 /* override the match function if necessary */ 00624 if (cb_fn == NULL) { /* if NULL, match everything */ 00625 if (type == WITH_DATA) { 00626 cb_withdata = cb_true_data; 00627 } else { 00628 cb_default = cb_true; 00629 } 00630 } else { 00631 /* We do this here to avoid the per object casting penalty (even though 00632 that is probably optimized away anyway). */ 00633 if (type == WITH_DATA) { 00634 cb_withdata = cb_fn; 00635 } else { 00636 cb_default = cb_fn; 00637 } 00638 } 00639 00640 /* 00641 * XXX this can be optimized. 00642 * If we have a hash function and lookup by pointer, 00643 * run the hash function. Otherwise, scan the whole container 00644 * (this only for the time being. We need to optimize this.) 00645 */ 00646 if ((flags & OBJ_POINTER)) /* we know hash can handle this case */ 00647 start = i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets; 00648 else /* don't know, let's scan all buckets */ 00649 start = i = -1; /* XXX this must be fixed later. */ 00650 00651 /* determine the search boundaries: i..last-1 */ 00652 if (i < 0) { 00653 start = i = 0; 00654 last = c->n_buckets; 00655 } else if ((flags & OBJ_CONTINUE)) { 00656 last = c->n_buckets; 00657 } else { 00658 last = i + 1; 00659 } 00660 00661 ao2_lock(c); /* avoid modifications to the content */ 00662 00663 for (; i < last ; i++) { 00664 /* scan the list with prev-cur pointers */ 00665 struct bucket_entry *cur; 00666 00667 AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) { 00668 int match = (CMP_MATCH | CMP_STOP); 00669 00670 if (type == WITH_DATA) { 00671 match &= cb_withdata(EXTERNAL_OBJ(cur->astobj), arg, data, flags); 00672 } else { 00673 match &= cb_default(EXTERNAL_OBJ(cur->astobj), arg, flags); 00674 } 00675 00676 /* we found the object, performing operations according flags */ 00677 if (match == 0) { /* no match, no stop, continue */ 00678 continue; 00679 } else if (match == CMP_STOP) { /* no match but stop, we are done */ 00680 i = last; 00681 break; 00682 } 00683 00684 /* we have a match (CMP_MATCH) here */ 00685 if (!(flags & OBJ_NODATA)) { /* if must return the object, record the value */ 00686 /* it is important to handle this case before the unlink */ 00687 ret = EXTERNAL_OBJ(cur->astobj); 00688 if (!(flags & (OBJ_UNLINK | OBJ_MULTIPLE))) { 00689 if (tag) 00690 __ao2_ref_debug(ret, 1, tag, file, line, funcname); 00691 else 00692 __ao2_ref(ret, 1); 00693 } 00694 } 00695 00696 /* If we are in OBJ_MULTIPLE mode and OBJ_NODATE is off, 00697 * link the object into the container that will hold the results. 00698 */ 00699 if (ret && (multi_container != NULL)) { 00700 if (tag) { 00701 __ao2_link_debug(multi_container, ret, tag, file, line, funcname); 00702 } else { 00703 __ao2_link(multi_container, ret); 00704 } 00705 ret = NULL; 00706 } 00707 00708 if (flags & OBJ_UNLINK) { /* must unlink */ 00709 /* we are going to modify the container, so update version */ 00710 ast_atomic_fetchadd_int(&c->version, 1); 00711 AST_LIST_REMOVE_CURRENT(entry); 00712 /* update number of elements */ 00713 ast_atomic_fetchadd_int(&c->elements, -1); 00714 00715 /* - When unlinking and not returning the result, (OBJ_NODATA), the ref from the container 00716 * must be decremented. 00717 * - When unlinking with OBJ_MULTIPLE the ref from the original container 00718 * must be decremented regardless if OBJ_NODATA is used. This is because the result is 00719 * returned in a new container that already holds its own ref for the object. If the ref 00720 * from the original container is not accounted for here a memory leak occurs. */ 00721 if (flags & (OBJ_NODATA | OBJ_MULTIPLE)) { 00722 if (tag) 00723 __ao2_ref_debug(EXTERNAL_OBJ(cur->astobj), -1, tag, file, line, funcname); 00724 else 00725 __ao2_ref(EXTERNAL_OBJ(cur->astobj), -1); 00726 } 00727 ast_free(cur); /* free the link record */ 00728 } 00729 00730 if ((match & CMP_STOP) || !(flags & OBJ_MULTIPLE)) { 00731 /* We found our only (or last) match, so force an exit from 00732 the outside loop. */ 00733 i = last; 00734 break; 00735 } 00736 } 00737 AST_LIST_TRAVERSE_SAFE_END; 00738 00739 if (ret) { 00740 break; 00741 } 00742 00743 if (i == c->n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) { 00744 /* Move to the beginning to ensure we check every bucket */ 00745 i = -1; 00746 last = start; 00747 } 00748 } 00749 ao2_unlock(c); 00750 00751 /* if multi_container was created, we are returning multiple objects */ 00752 if (multi_container != NULL) { 00753 *multi_iterator = ao2_iterator_init(multi_container, 00754 AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK | AO2_ITERATOR_MALLOCD); 00755 ao2_ref(multi_container, -1); 00756 return multi_iterator; 00757 } else { 00758 return ret; 00759 } 00760 }
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] |
Definition at line 408 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.
00410 { 00411 /* XXX maybe consistency check on arguments ? */ 00412 /* compute the container size */ 00413 00414 if (!c) 00415 return NULL; 00416 00417 c->version = 1; /* 0 is a reserved value here */ 00418 c->n_buckets = hash_fn ? n_buckets : 1; 00419 c->hash_fn = hash_fn ? hash_fn : hash_zero; 00420 c->cmp_fn = cmp_fn; 00421 00422 #ifdef AO2_DEBUG 00423 ast_atomic_fetchadd_int(&ao2.total_containers, 1); 00424 #endif 00425 00426 return c; 00427 }
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] |
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 834 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, bucket_entry::entry, 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().
00835 { 00836 int lim; 00837 struct bucket_entry *p = NULL; 00838 void *ret = NULL; 00839 00840 *q = NULL; 00841 00842 if (INTERNAL_OBJ(a->c) == NULL) 00843 return NULL; 00844 00845 if (!(a->flags & AO2_ITERATOR_DONTLOCK)) 00846 ao2_lock(a->c); 00847 00848 /* optimization. If the container is unchanged and 00849 * we have a pointer, try follow it 00850 */ 00851 if (a->c->version == a->c_version && (p = a->obj)) { 00852 if ((p = AST_LIST_NEXT(p, entry))) 00853 goto found; 00854 /* nope, start from the next bucket */ 00855 a->bucket++; 00856 a->version = 0; 00857 a->obj = NULL; 00858 } 00859 00860 lim = a->c->n_buckets; 00861 00862 /* Browse the buckets array, moving to the next 00863 * buckets if we don't find the entry in the current one. 00864 * Stop when we find an element with version number greater 00865 * than the current one (we reset the version to 0 when we 00866 * switch buckets). 00867 */ 00868 for (; a->bucket < lim; a->bucket++, a->version = 0) { 00869 /* scan the current bucket */ 00870 AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) { 00871 if (p->version > a->version) 00872 goto found; 00873 } 00874 } 00875 00876 found: 00877 if (p) { 00878 ret = EXTERNAL_OBJ(p->astobj); 00879 if (a->flags & AO2_ITERATOR_UNLINK) { 00880 /* we are going to modify the container, so update version */ 00881 ast_atomic_fetchadd_int(&a->c->version, 1); 00882 AST_LIST_REMOVE(&a->c->buckets[a->bucket], p, entry); 00883 /* update number of elements */ 00884 ast_atomic_fetchadd_int(&a->c->elements, -1); 00885 a->version = 0; 00886 a->obj = NULL; 00887 a->c_version = a->c->version; 00888 ast_free(p); 00889 } else { 00890 a->version = p->version; 00891 a->obj = p; 00892 a->c_version = a->c->version; 00893 /* inc refcount of returned object */ 00894 *q = p; 00895 } 00896 } 00897 00898 return ret; 00899 }
static struct bucket_entry * internal_ao2_link | ( | struct ao2_container * | c, | |
void * | user_data, | |||
const char * | file, | |||
int | line, | |||
const char * | func | |||
) | [static] |
Definition at line 478 of file astobj2.c.
References ao2_lock, ast_atomic_fetchadd_int(), ast_calloc, AST_LIST_INSERT_TAIL, bucket_entry::entry, INTERNAL_OBJ(), and OBJ_POINTER.
Referenced by __ao2_link(), and __ao2_link_debug().
00479 { 00480 int i; 00481 /* create a new list entry */ 00482 struct bucket_entry *p; 00483 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00484 00485 if (obj == NULL) 00486 return NULL; 00487 00488 if (INTERNAL_OBJ(c) == NULL) 00489 return NULL; 00490 00491 p = ast_calloc(1, sizeof(*p)); 00492 if (!p) 00493 return NULL; 00494 00495 i = abs(c->hash_fn(user_data, OBJ_POINTER)); 00496 00497 ao2_lock(c); 00498 i %= c->n_buckets; 00499 p->astobj = obj; 00500 p->version = ast_atomic_fetchadd_int(&c->version, 1); 00501 AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry); 00502 ast_atomic_fetchadd_int(&c->elements, 1); 00503 00504 /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */ 00505 return p; 00506 }
static int internal_ao2_ref | ( | void * | user_data, | |
const int | delta | |||
) | [static] |
Definition at line 240 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().
00241 { 00242 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00243 int current_value; 00244 int ret; 00245 00246 if (obj == NULL) 00247 return -1; 00248 00249 /* if delta is 0, just return the refcount */ 00250 if (delta == 0) 00251 return (obj->priv_data.ref_counter); 00252 00253 /* we modify with an atomic operation the reference counter */ 00254 ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta); 00255 current_value = ret + delta; 00256 00257 #ifdef AO2_DEBUG 00258 ast_atomic_fetchadd_int(&ao2.total_refs, delta); 00259 #endif 00260 00261 /* this case must never happen */ 00262 if (current_value < 0) 00263 ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data); 00264 00265 if (current_value <= 0) { /* last reference, destroy the object */ 00266 if (obj->priv_data.destructor_fn != NULL) { 00267 obj->priv_data.destructor_fn(user_data); 00268 } 00269 00270 ast_mutex_destroy(&obj->priv_data.lock); 00271 #ifdef AO2_DEBUG 00272 ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size); 00273 ast_atomic_fetchadd_int(&ao2.total_objects, -1); 00274 #endif 00275 /* for safety, zero-out the astobj2 header and also the 00276 * first word of the user-data, which we make sure is always 00277 * allocated. */ 00278 memset(obj, '\0', sizeof(struct astobj2 *) + sizeof(void *) ); 00279 ast_free(obj); 00280 } 00281 00282 return ret; 00283 }
static struct astobj2* INTERNAL_OBJ | ( | void * | user_data | ) | [inline, static] |
convert from a pointer _p to a user-defined object
Definition at line 110 of file astobj2.c.
References AO2_MAGIC, ast_log(), and LOG_ERROR.
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().
00111 { 00112 struct astobj2 *p; 00113 00114 if (!user_data) { 00115 ast_log(LOG_ERROR, "user_data is NULL\n"); 00116 return NULL; 00117 } 00118 00119 p = (struct astobj2 *) ((char *) user_data - sizeof(*p)); 00120 if (AO2_MAGIC != (p->priv_data.magic) ) { 00121 ast_log(LOG_ERROR, "bad magic number 0x%x for %p\n", p->priv_data.magic, p); 00122 p = NULL; 00123 } 00124 00125 return p; 00126 }