#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 133 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 338 of file astobj2.c.
References internal_ao2_alloc().
Referenced by __ao2_container_alloc().
00339 { 00340 return internal_ao2_alloc(data_size, destructor_fn, __FILE__, __LINE__, __FUNCTION__); 00341 }
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 317 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().
00319 { 00320 /* allocation */ 00321 void *obj; 00322 FILE *refo = ref_debug ? fopen(REF_FILE,"a") : NULL; 00323 00324 if ((obj = internal_ao2_alloc(data_size, destructor_fn, file, line, funcname)) == NULL) { 00325 fclose(refo); 00326 return NULL; 00327 } 00328 00329 if (refo) { 00330 fprintf(refo, "%p =1 %s:%d:%s (%s)\n", obj, file, line, funcname, tag); 00331 fclose(refo); 00332 } 00333 00334 /* return a pointer to the user data */ 00335 return obj; 00336 }
void* __ao2_callback | ( | struct ao2_container * | c, | |
const enum search_flags | flags, | |||
ao2_callback_fn * | cb_fn, | |||
void * | arg | |||
) |
Definition at line 762 of file astobj2.c.
References ao2_iterator::c, DEFAULT, and internal_ao2_callback().
Referenced by __ao2_find(), __ao2_unlink(), and container_destruct().
00764 { 00765 return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL); 00766 }
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 776 of file astobj2.c.
References ao2_iterator::c, internal_ao2_callback(), and WITH_DATA.
00778 { 00779 return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL); 00780 }
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 768 of file astobj2.c.
References ao2_iterator::c, internal_ao2_callback(), and WITH_DATA.
00772 { 00773 return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, funcname); 00774 }
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 754 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().
00758 { 00759 return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, funcname); 00760 }
struct ao2_container* __ao2_container_alloc | ( | const unsigned int | n_buckets, | |
ao2_hash_fn * | hash_fn, | |||
ao2_callback_fn * | cmp_fn | |||
) |
Definition at line 438 of file astobj2.c.
References __ao2_alloc(), container_destruct(), and internal_ao2_container_alloc().
Referenced by internal_ao2_callback().
00440 { 00441 /* XXX maybe consistency check on arguments ? */ 00442 /* compute the container size */ 00443 00444 const unsigned int num_buckets = hash_fn ? n_buckets : 1; 00445 size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket); 00446 struct ao2_container *c = __ao2_alloc(container_size, container_destruct); 00447 00448 return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn); 00449 }
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 425 of file astobj2.c.
References __ao2_alloc_debug(), container_destruct_debug(), and internal_ao2_container_alloc().
00428 { 00429 /* XXX maybe consistency check on arguments ? */ 00430 /* compute the container size */ 00431 const unsigned int num_buckets = hash_fn ? n_buckets : 1; 00432 size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket); 00433 struct ao2_container *c = __ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname, ref_debug); 00434 00435 return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn); 00436 }
void* __ao2_find | ( | struct ao2_container * | c, | |
void * | arg, | |||
enum search_flags | flags | |||
) |
Definition at line 790 of file astobj2.c.
References __ao2_callback(), ao2_iterator::c, and ao2_container::cmp_fn.
Referenced by _get_mohbyname().
00791 { 00792 return __ao2_callback(c, flags, c->cmp_fn, arg); 00793 }
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 785 of file astobj2.c.
References __ao2_callback_debug(), ao2_iterator::c, and ao2_container::cmp_fn.
Referenced by _get_mohbyname().
00786 { 00787 return __ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname); 00788 }
void* __ao2_iterator_next | ( | struct ao2_iterator * | a | ) |
Definition at line 911 of file astobj2.c.
References __ao2_ref(), AO2_ITERATOR_DONTLOCK, ao2_unlock, ao2_iterator::c, ao2_iterator::flags, and internal_ao2_iterator_next().
00912 { 00913 struct bucket_entry *p = NULL; 00914 void *ret = NULL; 00915 00916 ret = internal_ao2_iterator_next(a, &p); 00917 00918 if (p) { 00919 /* inc refcount of returned object */ 00920 __ao2_ref(ret, 1); 00921 } 00922 00923 if (!(a->flags & AO2_ITERATOR_DONTLOCK)) 00924 ao2_unlock(a->c); 00925 00926 return ret; 00927 }
void* __ao2_iterator_next_debug | ( | struct ao2_iterator * | a, | |
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 893 of file astobj2.c.
References __ao2_ref_debug(), AO2_ITERATOR_DONTLOCK, ao2_unlock, ao2_iterator::c, ao2_iterator::flags, and internal_ao2_iterator_next().
00894 { 00895 struct bucket_entry *p; 00896 void *ret = NULL; 00897 00898 ret = internal_ao2_iterator_next(a, &p); 00899 00900 if (p) { 00901 /* inc refcount of returned object */ 00902 __ao2_ref_debug(ret, 1, tag, file, line, funcname); 00903 } 00904 00905 if (!(a->flags & AO2_ITERATOR_DONTLOCK)) 00906 ao2_unlock(a->c); 00907 00908 return ret; 00909 }
void* __ao2_link | ( | struct ao2_container * | c, | |
void * | user_data | |||
) |
Definition at line 515 of file astobj2.c.
References __ao2_ref(), ao2_unlock, and internal_ao2_link().
Referenced by internal_ao2_callback().
00516 { 00517 struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__); 00518 00519 if (p) { 00520 __ao2_ref(user_data, +1); 00521 ao2_unlock(c); 00522 } 00523 return p; 00524 }
void* __ao2_link_debug | ( | struct ao2_container * | c, | |
void * | user_data, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 504 of file astobj2.c.
References __ao2_ref_debug(), ao2_unlock, and internal_ao2_link().
00505 { 00506 struct bucket_entry *p = internal_ao2_link(c, user_data, file, line, funcname); 00507 00508 if (p) { 00509 __ao2_ref_debug(user_data, +1, tag, file, line, funcname); 00510 ao2_unlock(c); 00511 } 00512 return p; 00513 }
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 146 of file astobj2.c.
References __ast_pthread_mutex_lock(), ast_atomic_fetchadd_int(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00147 { 00148 struct astobj2 *p = INTERNAL_OBJ(user_data); 00149 00150 if (p == NULL) 00151 return -1; 00152 00153 #ifdef AO2_DEBUG 00154 ast_atomic_fetchadd_int(&ao2.total_locked, 1); 00155 #endif 00156 00157 return __ast_pthread_mutex_lock(file, line, func, var, &p->priv_data.lock); 00158 }
int __ao2_ref | ( | void * | user_data, | |
const int | delta | |||
) |
Definition at line 225 of file astobj2.c.
References internal_ao2_ref(), and INTERNAL_OBJ().
Referenced by __ao2_iterator_next(), __ao2_link(), cd_cb(), and internal_ao2_callback().
00226 { 00227 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00228 00229 if (obj == NULL) 00230 return -1; 00231 00232 return internal_ao2_ref(user_data, delta); 00233 }
int __ao2_ref_debug | ( | void * | user_data, | |
const int | delta, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 205 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().
00206 { 00207 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00208 00209 if (obj == NULL) 00210 return -1; 00211 00212 if (delta != 0) { 00213 FILE *refo = fopen(REF_FILE,"a"); 00214 fprintf(refo, "%p %s%d %s:%d:%s (%s) [@%d]\n", user_data, (delta<0? "":"+"), delta, file, line, funcname, tag, obj ? obj->priv_data.ref_counter : -1); 00215 fclose(refo); 00216 } 00217 if (obj->priv_data.ref_counter + delta == 0 && obj->priv_data.destructor_fn != NULL) { /* this isn't protected with lock; just for o/p */ 00218 FILE *refo = fopen(REF_FILE,"a"); 00219 fprintf(refo, "%p **call destructor** %s:%d:%s (%s)\n", user_data, file, line, funcname, tag); 00220 fclose(refo); 00221 } 00222 return internal_ao2_ref(user_data, delta); 00223 }
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 174 of file astobj2.c.
References __ast_pthread_mutex_trylock(), ast_atomic_fetchadd_int(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00175 { 00176 struct astobj2 *p = INTERNAL_OBJ(user_data); 00177 int ret; 00178 00179 if (p == NULL) 00180 return -1; 00181 ret = __ast_pthread_mutex_trylock(file, line, func, var, &p->priv_data.lock); 00182 00183 #ifdef AO2_DEBUG 00184 if (!ret) 00185 ast_atomic_fetchadd_int(&ao2.total_locked, 1); 00186 #endif 00187 return ret; 00188 }
void* __ao2_unlink | ( | struct ao2_container * | c, | |
void * | user_data | |||
) |
Definition at line 549 of file astobj2.c.
References __ao2_callback(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.
00550 { 00551 if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */ 00552 return NULL; 00553 00554 __ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data); 00555 00556 return NULL; 00557 }
void* __ao2_unlink_debug | ( | struct ao2_container * | c, | |
void * | user_data, | |||
char * | tag, | |||
char * | file, | |||
int | line, | |||
const char * | funcname | |||
) |
Definition at line 538 of file astobj2.c.
References __ao2_callback_debug(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.
00540 { 00541 if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */ 00542 return NULL; 00543 00544 __ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname); 00545 00546 return NULL; 00547 }
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 160 of file astobj2.c.
References __ast_pthread_mutex_unlock(), ast_atomic_fetchadd_int(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00161 { 00162 struct astobj2 *p = INTERNAL_OBJ(user_data); 00163 00164 if (p == NULL) 00165 return -1; 00166 00167 #ifdef AO2_DEBUG 00168 ast_atomic_fetchadd_int(&ao2.total_locked, -1); 00169 #endif 00170 00171 return __ast_pthread_mutex_unlock(file, line, func, var, &p->priv_data.lock); 00172 }
void ao2_bt | ( | void | ) |
Definition at line 83 of file astobj2.c.
References ast_bt_get_symbols(), ast_verbose, free, and N1.
00084 { 00085 int c, i; 00086 #define N1 20 00087 void *addresses[N1]; 00088 char **strings; 00089 00090 c = backtrace(addresses, N1); 00091 strings = ast_bt_get_symbols(addresses,c); 00092 ast_verbose("backtrace returned: %d\n", c); 00093 for(i = 0; i < c; i++) { 00094 ast_verbose("%d: %p %s\n", i, addresses[i], strings[i]); 00095 } 00096 free(strings); 00097 }
int ao2_container_count | ( | struct ao2_container * | c | ) |
Returns the number of elements in a container.
return the number of elements in the container
Definition at line 454 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_tone_zone_count(), cc_cli_output_status(), cleanup(), cli_fax_show_sessions(), cli_tps_report(), data_odbc_provider_handler(), data_provider_release(), data_provider_release_all(), 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(), and unload_module().
00455 { 00456 return c->elements; 00457 }
void ao2_iterator_destroy | ( | struct ao2_iterator * | i | ) |
Destroy a container iterator.
destroy an iterator
Definition at line 813 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(), astman_verify_session_readpermissions(), astman_verify_session_writepermissions(), authenticate(), authenticate_reply(), calendar_query_exec(), check_access(), clear_queue(), clear_stats(), cli_console_active(), cli_fax_show_sessions(), cli_list_devices(), compare_weight(), complete_core_id(), complete_core_show_hint(), 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_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_moh_show_classes(), handle_cli_moh_show_files(), handle_cli_odbc_show(), handle_feature_show(), 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(), local_devicestate(), locals_show(), manager_iax2_show_peer_list(), manager_optimize_away(), 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(), 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(), unload_module(), update_queue(), update_realtime_members(), and users_data_provider_get().
00814 { 00815 ao2_ref(i->c, -1); 00816 if (i->flags & AO2_ITERATOR_MALLOCD) { 00817 ast_free(i); 00818 } else { 00819 i->c = NULL; 00820 } 00821 }
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 798 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(), _sip_show_peers(), 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(), 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().
00799 { 00800 struct ao2_iterator a = { 00801 .c = c, 00802 .flags = flags 00803 }; 00804 00805 ao2_ref(c, +1); 00806 00807 return a; 00808 }
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 190 of file astobj2.c.
References INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.
00191 { 00192 struct astobj2 *p = INTERNAL_OBJ(obj); 00193 00194 if (p == NULL) 00195 return NULL; 00196 00197 return &p->priv_data.lock; 00198 }
int astobj2_init | ( | void | ) |
Provided by astobj2.c
Definition at line 1117 of file astobj2.c.
References ARRAY_LEN, and ast_cli_register_multiple().
Referenced by main().
01118 { 01119 #ifdef AO2_DEBUG 01120 ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2)); 01121 #endif 01122 01123 return 0; 01124 }
static int cb_true | ( | void * | user_data, | |
void * | arg, | |||
int | flags | |||
) | [static] |
special callback that matches all
Definition at line 562 of file astobj2.c.
References CMP_MATCH.
Referenced by internal_ao2_callback().
00563 { 00564 return CMP_MATCH; 00565 }
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 570 of file astobj2.c.
References CMP_MATCH.
Referenced by internal_ao2_callback().
00571 { 00572 return CMP_MATCH; 00573 }
static int cd_cb | ( | void * | obj, | |
void * | arg, | |||
int | flag | |||
) | [static] |
Definition at line 932 of file astobj2.c.
References __ao2_ref().
Referenced by container_destruct().
00933 { 00934 __ao2_ref(obj, -1); 00935 return 0; 00936 }
static int cd_cb_debug | ( | void * | obj, | |
void * | arg, | |||
int | flag | |||
) | [static] |
Definition at line 938 of file astobj2.c.
References __ao2_ref_debug().
Referenced by container_destruct_debug().
00939 { 00940 __ao2_ref_debug(obj, -1, "deref object via container destroy", __FILE__, __LINE__, __PRETTY_FUNCTION__); 00941 return 0; 00942 }
static void container_destruct | ( | void * | c | ) | [static] |
Definition at line 944 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().
00945 { 00946 struct ao2_container *c = _c; 00947 int i; 00948 00949 __ao2_callback(c, OBJ_UNLINK, cd_cb, NULL); 00950 00951 for (i = 0; i < c->n_buckets; i++) { 00952 struct bucket_entry *current; 00953 00954 while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) { 00955 ast_free(current); 00956 } 00957 } 00958 00959 #ifdef AO2_DEBUG 00960 ast_atomic_fetchadd_int(&ao2.total_containers, -1); 00961 #endif 00962 }
static void container_destruct_debug | ( | void * | c | ) | [static] |
Definition at line 964 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().
00965 { 00966 struct ao2_container *c = _c; 00967 int i; 00968 00969 __ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__); 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 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 396 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 284 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().
00285 { 00286 /* allocation */ 00287 struct astobj2 *obj; 00288 00289 if (data_size < sizeof(void *)) 00290 data_size = sizeof(void *); 00291 00292 #if defined(__AST_DEBUG_MALLOC) 00293 obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, funcname); 00294 #else 00295 obj = ast_calloc(1, sizeof(*obj) + data_size); 00296 #endif 00297 00298 if (obj == NULL) 00299 return NULL; 00300 00301 ast_mutex_init(&obj->priv_data.lock); 00302 obj->priv_data.magic = AO2_MAGIC; 00303 obj->priv_data.data_size = data_size; 00304 obj->priv_data.ref_counter = 1; 00305 obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */ 00306 00307 #ifdef AO2_DEBUG 00308 ast_atomic_fetchadd_int(&ao2.total_objects, 1); 00309 ast_atomic_fetchadd_int(&ao2.total_mem, data_size); 00310 ast_atomic_fetchadd_int(&ao2.total_refs, 1); 00311 #endif 00312 00313 /* return a pointer to the user data */ 00314 return EXTERNAL_OBJ(obj); 00315 }
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 583 of file astobj2.c.
References __ao2_container_alloc(), __ao2_link(), __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().
00586 { 00587 int i, start, last; /* search boundaries */ 00588 void *ret = NULL; 00589 ao2_callback_fn *cb_default = NULL; 00590 ao2_callback_data_fn *cb_withdata = NULL; 00591 struct ao2_container *multi_container = NULL; 00592 struct ao2_iterator *multi_iterator = NULL; 00593 00594 if (INTERNAL_OBJ(c) == NULL) /* safety check on the argument */ 00595 return NULL; 00596 00597 /* 00598 * This logic is used so we can support OBJ_MULTIPLE with OBJ_NODATA 00599 * turned off. This if statement checks for the special condition 00600 * where multiple items may need to be returned. 00601 */ 00602 if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) { 00603 /* we need to return an ao2_iterator with the results, 00604 * as there could be more than one. the iterator will 00605 * hold the only reference to a container that has all the 00606 * matching objects linked into it, so when the iterator 00607 * is destroyed, the container will be automatically 00608 * destroyed as well. 00609 */ 00610 if (!(multi_container = __ao2_container_alloc(1, NULL, NULL))) { 00611 return NULL; 00612 } 00613 if (!(multi_iterator = ast_calloc(1, sizeof(*multi_iterator)))) { 00614 ao2_ref(multi_container, -1); 00615 return NULL; 00616 } 00617 } 00618 00619 /* override the match function if necessary */ 00620 if (cb_fn == NULL) { /* if NULL, match everything */ 00621 if (type == WITH_DATA) { 00622 cb_withdata = cb_true_data; 00623 } else { 00624 cb_default = cb_true; 00625 } 00626 } else { 00627 /* We do this here to avoid the per object casting penalty (even though 00628 that is probably optimized away anyway). */ 00629 if (type == WITH_DATA) { 00630 cb_withdata = cb_fn; 00631 } else { 00632 cb_default = cb_fn; 00633 } 00634 } 00635 00636 /* 00637 * XXX this can be optimized. 00638 * If we have a hash function and lookup by pointer, 00639 * run the hash function. Otherwise, scan the whole container 00640 * (this only for the time being. We need to optimize this.) 00641 */ 00642 if ((flags & OBJ_POINTER)) /* we know hash can handle this case */ 00643 start = i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets; 00644 else /* don't know, let's scan all buckets */ 00645 start = i = -1; /* XXX this must be fixed later. */ 00646 00647 /* determine the search boundaries: i..last-1 */ 00648 if (i < 0) { 00649 start = i = 0; 00650 last = c->n_buckets; 00651 } else if ((flags & OBJ_CONTINUE)) { 00652 last = c->n_buckets; 00653 } else { 00654 last = i + 1; 00655 } 00656 00657 ao2_lock(c); /* avoid modifications to the content */ 00658 00659 for (; i < last ; i++) { 00660 /* scan the list with prev-cur pointers */ 00661 struct bucket_entry *cur; 00662 00663 AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) { 00664 int match = (CMP_MATCH | CMP_STOP); 00665 00666 if (type == WITH_DATA) { 00667 match &= cb_withdata(EXTERNAL_OBJ(cur->astobj), arg, data, flags); 00668 } else { 00669 match &= cb_default(EXTERNAL_OBJ(cur->astobj), arg, flags); 00670 } 00671 00672 /* we found the object, performing operations according flags */ 00673 if (match == 0) { /* no match, no stop, continue */ 00674 continue; 00675 } else if (match == CMP_STOP) { /* no match but stop, we are done */ 00676 i = last; 00677 break; 00678 } 00679 00680 /* we have a match (CMP_MATCH) here */ 00681 if (!(flags & OBJ_NODATA)) { /* if must return the object, record the value */ 00682 /* it is important to handle this case before the unlink */ 00683 ret = EXTERNAL_OBJ(cur->astobj); 00684 if (!(flags & (OBJ_UNLINK | OBJ_MULTIPLE))) { 00685 if (tag) 00686 __ao2_ref_debug(ret, 1, tag, file, line, funcname); 00687 else 00688 __ao2_ref(ret, 1); 00689 } 00690 } 00691 00692 /* If we are in OBJ_MULTIPLE mode and OBJ_NODATE is off, 00693 * link the object into the container that will hold the results. 00694 */ 00695 if (ret && (multi_container != NULL)) { 00696 __ao2_link(multi_container, ret); 00697 ret = NULL; 00698 } 00699 00700 if (flags & OBJ_UNLINK) { /* must unlink */ 00701 /* we are going to modify the container, so update version */ 00702 ast_atomic_fetchadd_int(&c->version, 1); 00703 AST_LIST_REMOVE_CURRENT(entry); 00704 /* update number of elements */ 00705 ast_atomic_fetchadd_int(&c->elements, -1); 00706 00707 /* - When unlinking and not returning the result, (OBJ_NODATA), the ref from the container 00708 * must be decremented. 00709 * - When unlinking with OBJ_MULTIPLE the ref from the original container 00710 * must be decremented regardless if OBJ_NODATA is used. This is because the result is 00711 * returned in a new container that already holds its own ref for the object. If the ref 00712 * from the original container is not accounted for here a memory leak occurs. */ 00713 if (flags & (OBJ_NODATA | OBJ_MULTIPLE)) { 00714 if (tag) 00715 __ao2_ref_debug(EXTERNAL_OBJ(cur->astobj), -1, tag, file, line, funcname); 00716 else 00717 __ao2_ref(EXTERNAL_OBJ(cur->astobj), -1); 00718 } 00719 ast_free(cur); /* free the link record */ 00720 } 00721 00722 if ((match & CMP_STOP) || !(flags & OBJ_MULTIPLE)) { 00723 /* We found our only (or last) match, so force an exit from 00724 the outside loop. */ 00725 i = last; 00726 break; 00727 } 00728 } 00729 AST_LIST_TRAVERSE_SAFE_END; 00730 00731 if (ret) { 00732 break; 00733 } 00734 00735 if (i == c->n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) { 00736 /* Move to the beginning to ensure we check every bucket */ 00737 i = -1; 00738 last = start; 00739 } 00740 } 00741 ao2_unlock(c); 00742 00743 /* if multi_container was created, we are returning multiple objects */ 00744 if (multi_container != NULL) { 00745 *multi_iterator = ao2_iterator_init(multi_container, 00746 AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK | AO2_ITERATOR_MALLOCD); 00747 ao2_ref(multi_container, -1); 00748 return multi_iterator; 00749 } else { 00750 return ret; 00751 } 00752 }
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 404 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.
00406 { 00407 /* XXX maybe consistency check on arguments ? */ 00408 /* compute the container size */ 00409 00410 if (!c) 00411 return NULL; 00412 00413 c->version = 1; /* 0 is a reserved value here */ 00414 c->n_buckets = hash_fn ? n_buckets : 1; 00415 c->hash_fn = hash_fn ? hash_fn : hash_zero; 00416 c->cmp_fn = cmp_fn; 00417 00418 #ifdef AO2_DEBUG 00419 ast_atomic_fetchadd_int(&ao2.total_containers, 1); 00420 #endif 00421 00422 return c; 00423 }
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 826 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().
00827 { 00828 int lim; 00829 struct bucket_entry *p = NULL; 00830 void *ret = NULL; 00831 00832 *q = NULL; 00833 00834 if (INTERNAL_OBJ(a->c) == NULL) 00835 return NULL; 00836 00837 if (!(a->flags & AO2_ITERATOR_DONTLOCK)) 00838 ao2_lock(a->c); 00839 00840 /* optimization. If the container is unchanged and 00841 * we have a pointer, try follow it 00842 */ 00843 if (a->c->version == a->c_version && (p = a->obj)) { 00844 if ((p = AST_LIST_NEXT(p, entry))) 00845 goto found; 00846 /* nope, start from the next bucket */ 00847 a->bucket++; 00848 a->version = 0; 00849 a->obj = NULL; 00850 } 00851 00852 lim = a->c->n_buckets; 00853 00854 /* Browse the buckets array, moving to the next 00855 * buckets if we don't find the entry in the current one. 00856 * Stop when we find an element with version number greater 00857 * than the current one (we reset the version to 0 when we 00858 * switch buckets). 00859 */ 00860 for (; a->bucket < lim; a->bucket++, a->version = 0) { 00861 /* scan the current bucket */ 00862 AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) { 00863 if (p->version > a->version) 00864 goto found; 00865 } 00866 } 00867 00868 found: 00869 if (p) { 00870 ret = EXTERNAL_OBJ(p->astobj); 00871 if (a->flags & AO2_ITERATOR_UNLINK) { 00872 /* we are going to modify the container, so update version */ 00873 ast_atomic_fetchadd_int(&a->c->version, 1); 00874 AST_LIST_REMOVE(&a->c->buckets[a->bucket], p, entry); 00875 /* update number of elements */ 00876 ast_atomic_fetchadd_int(&a->c->elements, -1); 00877 a->version = 0; 00878 a->obj = NULL; 00879 a->c_version = a->c->version; 00880 ast_free(p); 00881 } else { 00882 a->version = p->version; 00883 a->obj = p; 00884 a->c_version = a->c->version; 00885 /* inc refcount of returned object */ 00886 *q = p; 00887 } 00888 } 00889 00890 return ret; 00891 }
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 474 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().
00475 { 00476 int i; 00477 /* create a new list entry */ 00478 struct bucket_entry *p; 00479 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00480 00481 if (obj == NULL) 00482 return NULL; 00483 00484 if (INTERNAL_OBJ(c) == NULL) 00485 return NULL; 00486 00487 p = ast_calloc(1, sizeof(*p)); 00488 if (!p) 00489 return NULL; 00490 00491 i = abs(c->hash_fn(user_data, OBJ_POINTER)); 00492 00493 ao2_lock(c); 00494 i %= c->n_buckets; 00495 p->astobj = obj; 00496 p->version = ast_atomic_fetchadd_int(&c->version, 1); 00497 AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry); 00498 ast_atomic_fetchadd_int(&c->elements, 1); 00499 00500 /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */ 00501 return p; 00502 }
static int internal_ao2_ref | ( | void * | user_data, | |
const int | delta | |||
) | [static] |
Definition at line 235 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().
00236 { 00237 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00238 int current_value; 00239 int ret; 00240 00241 if (obj == NULL) 00242 return -1; 00243 00244 /* if delta is 0, just return the refcount */ 00245 if (delta == 0) 00246 return (obj->priv_data.ref_counter); 00247 00248 /* we modify with an atomic operation the reference counter */ 00249 ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta); 00250 current_value = ret + delta; 00251 00252 #ifdef AO2_DEBUG 00253 ast_atomic_fetchadd_int(&ao2.total_refs, delta); 00254 #endif 00255 00256 /* this case must never happen */ 00257 if (current_value < 0) 00258 ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data); 00259 00260 if (current_value <= 0) { /* last reference, destroy the object */ 00261 if (obj->priv_data.destructor_fn != NULL) { 00262 obj->priv_data.destructor_fn(user_data); 00263 } 00264 00265 ast_mutex_destroy(&obj->priv_data.lock); 00266 #ifdef AO2_DEBUG 00267 ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size); 00268 ast_atomic_fetchadd_int(&ao2.total_objects, -1); 00269 #endif 00270 /* for safety, zero-out the astobj2 header and also the 00271 * first word of the user-data, which we make sure is always 00272 * allocated. */ 00273 memset(obj, '\0', sizeof(struct astobj2 *) + sizeof(void *) ); 00274 ast_free(obj); 00275 } 00276 00277 return ret; 00278 }
static struct astobj2* INTERNAL_OBJ | ( | void * | user_data | ) | [inline, static] |
convert from a pointer _p to a user-defined object
Definition at line 105 of file astobj2.c.
References AO2_MAGIC, ast_log(), and LOG_ERROR.
Referenced by __ao2_lock(), __ao2_ref(), __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().
00106 { 00107 struct astobj2 *p; 00108 00109 if (!user_data) { 00110 ast_log(LOG_ERROR, "user_data is NULL\n"); 00111 return NULL; 00112 } 00113 00114 p = (struct astobj2 *) ((char *) user_data - sizeof(*p)); 00115 if (AO2_MAGIC != (p->priv_data.magic) ) { 00116 ast_log(LOG_ERROR, "bad magic number 0x%x for %p\n", p->priv_data.magic, p); 00117 p = NULL; 00118 } 00119 00120 return p; 00121 }