Tue Aug 20 16:34:47 2013

Asterisk developer's documentation


astobj2.c File Reference

#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)
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.
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_containerinternal_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_containerinternal_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_entryinternal_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 astobj2INTERNAL_OBJ (void *user_data)
 convert from a pointer _p to a user-defined object

Define Documentation

#define AO2_MAGIC   0xa570b123

Definition at line 56 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

Returns:
the pointer to the user-defined portion.

Definition at line 145 of file astobj2.c.

Referenced by internal_ao2_alloc(), internal_ao2_callback(), and internal_ao2_iterator_next().

#define N1   20

Referenced by ao2_bt().

#define REF_FILE   "/tmp/refs"

Definition at line 33 of file astobj2.c.

Referenced by __ao2_alloc_debug(), and __ao2_ref_debug().


Enumeration Type Documentation

Enumerator:
DEFAULT 
WITH_DATA 

Definition at line 135 of file astobj2.c.

00135                        {
00136    DEFAULT,
00137    WITH_DATA,
00138 };


Function Documentation

void* __ao2_alloc ( size_t  data_size,
ao2_destructor_fn  destructor_fn 
)

Definition at line 349 of file astobj2.c.

References internal_ao2_alloc().

Referenced by __ao2_container_alloc().

00350 {
00351    return internal_ao2_alloc(data_size, destructor_fn, __FILE__, __LINE__, __FUNCTION__);
00352 }

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 329 of file astobj2.c.

References internal_ao2_alloc(), and REF_FILE.

Referenced by __ao2_container_alloc_debug(), __ast_channel_alloc_ap(), __ast_dummy_channel_alloc(), and _moh_class_malloc().

00331 {
00332    /* allocation */
00333    void *obj;
00334    FILE *refo;
00335 
00336    if ((obj = internal_ao2_alloc(data_size, destructor_fn, file, line, funcname)) == NULL) {
00337       return NULL;
00338    }
00339 
00340    if (ref_debug && (refo = fopen(REF_FILE, "a"))) {
00341       fprintf(refo, "%p =1   %s:%d:%s (%s)\n", obj, file, line, funcname, tag);
00342       fclose(refo);
00343    }
00344 
00345    /* return a pointer to the user data */
00346    return obj;
00347 }

void* __ao2_callback ( struct ao2_container c,
const enum search_flags  flags,
ao2_callback_fn cb_fn,
void *  arg 
)

Definition at line 777 of file astobj2.c.

References DEFAULT, and internal_ao2_callback().

Referenced by __ao2_find(), __ao2_unlink(), and container_destruct().

00779 {
00780    return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL);
00781 }

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 791 of file astobj2.c.

References internal_ao2_callback(), and WITH_DATA.

00793 {
00794    return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL);
00795 }

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 783 of file astobj2.c.

References internal_ao2_callback(), and WITH_DATA.

00787 {
00788    return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, funcname);
00789 }

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 769 of file astobj2.c.

References DEFAULT, and internal_ao2_callback().

Referenced by __ao2_find_debug(), __ao2_unlink_debug(), and container_destruct_debug().

00773 {
00774    return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, funcname);
00775 }

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 449 of file astobj2.c.

References __ao2_alloc(), container_destruct(), and internal_ao2_container_alloc().

Referenced by internal_ao2_callback().

00451 {
00452    /* XXX maybe consistency check on arguments ? */
00453    /* compute the container size */
00454 
00455    const unsigned int num_buckets = hash_fn ? n_buckets : 1;
00456    size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket);
00457    struct ao2_container *c = __ao2_alloc(container_size, container_destruct);
00458 
00459    return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn);
00460 }

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 436 of file astobj2.c.

References __ao2_alloc_debug(), container_destruct_debug(), and internal_ao2_container_alloc().

00439 {
00440    /* XXX maybe consistency check on arguments ? */
00441    /* compute the container size */
00442    const unsigned int num_buckets = hash_fn ? n_buckets : 1;
00443    size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket);
00444    struct ao2_container *c = __ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname, ref_debug);
00445 
00446    return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn);
00447 }

void* __ao2_find ( struct ao2_container c,
void *  arg,
enum search_flags  flags 
)

Definition at line 805 of file astobj2.c.

References __ao2_callback(), and ao2_container::cmp_fn.

Referenced by _get_mohbyname().

00806 {
00807    return __ao2_callback(c, flags, c->cmp_fn, arg);
00808 }

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 800 of file astobj2.c.

References __ao2_callback_debug(), and ao2_container::cmp_fn.

Referenced by _get_mohbyname().

00801 {
00802    return __ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname);
00803 }

void* __ao2_iterator_next ( struct ao2_iterator a  ) 

Definition at line 926 of file astobj2.c.

References __ao2_ref(), AO2_ITERATOR_DONTLOCK, ao2_unlock, ao2_iterator::c, ao2_iterator::flags, and internal_ao2_iterator_next().

00927 {
00928    struct bucket_entry *p = NULL;
00929    void *ret = NULL;
00930 
00931    ret = internal_ao2_iterator_next(a, &p);
00932    
00933    if (p) {
00934       /* inc refcount of returned object */
00935       __ao2_ref(ret, 1);
00936    }
00937 
00938    if (!(a->flags & AO2_ITERATOR_DONTLOCK))
00939       ao2_unlock(a->c);
00940 
00941    return ret;
00942 }

void* __ao2_iterator_next_debug ( struct ao2_iterator a,
char *  tag,
char *  file,
int  line,
const char *  funcname 
)

Definition at line 908 of file astobj2.c.

References __ao2_ref_debug(), AO2_ITERATOR_DONTLOCK, ao2_unlock, ao2_iterator::c, ao2_iterator::flags, and internal_ao2_iterator_next().

00909 {
00910    struct bucket_entry *p;
00911    void *ret = NULL;
00912 
00913    ret = internal_ao2_iterator_next(a, &p);
00914    
00915    if (p) {
00916       /* inc refcount of returned object */
00917       __ao2_ref_debug(ret, 1, tag, file, line, funcname);
00918    }
00919 
00920    if (!(a->flags & AO2_ITERATOR_DONTLOCK))
00921       ao2_unlock(a->c);
00922 
00923    return ret;
00924 }

void* __ao2_link ( struct ao2_container c,
void *  user_data 
)

Definition at line 526 of file astobj2.c.

References __ao2_ref(), ao2_unlock, and internal_ao2_link().

Referenced by internal_ao2_callback().

00527 {
00528    struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
00529 
00530    if (p) {
00531       __ao2_ref(user_data, +1);
00532       ao2_unlock(c);
00533    }
00534    return p;
00535 }

void* __ao2_link_debug ( struct ao2_container c,
void *  user_data,
char *  tag,
char *  file,
int  line,
const char *  funcname 
)

Definition at line 515 of file astobj2.c.

References __ao2_ref_debug(), 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, funcname);
00518 
00519    if (p) {
00520       __ao2_ref_debug(user_data, +1, tag, file, line, funcname);
00521       ao2_unlock(c);
00522    }
00523    return p;
00524 }

int __ao2_lock ( void *  a,
const char *  file,
const char *  func,
int  line,
const char *  var 
)

Lock an object.

Parameters:
a A pointer to the object we want to lock.
Returns:
0 on success, other values on error.

Definition at line 158 of file astobj2.c.

References __ast_pthread_mutex_lock(), ast_atomic_fetchadd_int(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.

00159 {
00160    struct astobj2 *p = INTERNAL_OBJ(user_data);
00161 
00162    if (p == NULL)
00163       return -1;
00164 
00165 #ifdef AO2_DEBUG
00166    ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00167 #endif
00168 
00169    return __ast_pthread_mutex_lock(file, line, func, var, &p->priv_data.lock);
00170 }

int __ao2_ref ( void *  user_data,
const int  delta 
)

Definition at line 242 of file astobj2.c.

References internal_ao2_ref().

Referenced by __ao2_iterator_next(), __ao2_link(), cd_cb(), and internal_ao2_callback().

00243 {
00244    return internal_ao2_ref(user_data, delta);
00245 }

int __ao2_ref_debug ( void *  user_data,
const int  delta,
const char *  tag,
const char *  file,
int  line,
const char *  funcname 
)

Definition at line 217 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().

00218 {
00219    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00220    
00221    if (obj == NULL)
00222       return -1;
00223 
00224    if (delta != 0) {
00225       FILE *refo = fopen(REF_FILE, "a");
00226       if (refo) {
00227          fprintf(refo, "%p %s%d   %s:%d:%s (%s) [@%d]\n", user_data, (delta < 0 ? "" : "+"),
00228             delta, file, line, funcname, tag, obj ? obj->priv_data.ref_counter : -1);
00229          fclose(refo);
00230       }
00231    }
00232    if (obj->priv_data.ref_counter + delta == 0 && obj->priv_data.destructor_fn != NULL) { /* this isn't protected with lock; just for o/p */
00233       FILE *refo = fopen(REF_FILE, "a");
00234       if (refo) {
00235          fprintf(refo, "%p **call destructor** %s:%d:%s (%s)\n", user_data, file, line, funcname, tag);
00236          fclose(refo);
00237       }
00238    }
00239    return internal_ao2_ref(user_data, delta);
00240 }

int __ao2_trylock ( void *  a,
const char *  file,
const char *  func,
int  line,
const char *  var 
)

Try locking-- (don't block if fail).

Parameters:
a A pointer to the object we want to lock.
Returns:
0 on success, other values on error.

Definition at line 186 of file astobj2.c.

References __ast_pthread_mutex_trylock(), ast_atomic_fetchadd_int(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.

00187 {
00188    struct astobj2 *p = INTERNAL_OBJ(user_data);
00189    int ret;
00190    
00191    if (p == NULL)
00192       return -1;
00193    ret = __ast_pthread_mutex_trylock(file, line, func, var, &p->priv_data.lock);
00194 
00195 #ifdef AO2_DEBUG
00196    if (!ret)
00197       ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00198 #endif
00199    return ret;
00200 }

void* __ao2_unlink ( struct ao2_container c,
void *  user_data 
)

Definition at line 560 of file astobj2.c.

References __ao2_callback(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.

00561 {
00562    if (INTERNAL_OBJ(user_data) == NULL)   /* safety check on the argument */
00563       return NULL;
00564 
00565    __ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
00566 
00567    return NULL;
00568 }

void* __ao2_unlink_debug ( struct ao2_container c,
void *  user_data,
char *  tag,
char *  file,
int  line,
const char *  funcname 
)

Definition at line 549 of file astobj2.c.

References __ao2_callback_debug(), ao2_match_by_addr, INTERNAL_OBJ(), OBJ_NODATA, OBJ_POINTER, and OBJ_UNLINK.

00551 {
00552    if (INTERNAL_OBJ(user_data) == NULL)   /* safety check on the argument */
00553       return NULL;
00554 
00555    __ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
00556 
00557    return NULL;
00558 }

int __ao2_unlock ( void *  a,
const char *  file,
const char *  func,
int  line,
const char *  var 
)

Unlock an object.

Parameters:
a A pointer to the object we want unlock.
Returns:
0 on success, other values on error.

Definition at line 172 of file astobj2.c.

References __ast_pthread_mutex_unlock(), ast_atomic_fetchadd_int(), INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.

00173 {
00174    struct astobj2 *p = INTERNAL_OBJ(user_data);
00175 
00176    if (p == NULL)
00177       return -1;
00178 
00179 #ifdef AO2_DEBUG
00180    ast_atomic_fetchadd_int(&ao2.total_locked, -1);
00181 #endif
00182 
00183    return __ast_pthread_mutex_unlock(file, line, func, var, &p->priv_data.lock);
00184 }

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  ) 
void ao2_iterator_destroy ( struct ao2_iterator i  ) 

Destroy a container iterator.

destroy an iterator

Definition at line 828 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_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(), 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(), try_calling(), unload_module(), update_queue(), update_realtime_members(), and users_data_provider_get().

00829 {
00830    ao2_ref(i->c, -1);
00831    if (i->flags & AO2_ITERATOR_MALLOCD) {
00832       ast_free(i);
00833    } else {
00834       i->c = NULL;
00835    }
00836 }

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 813 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_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(), 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(), try_calling(), unload_module(), update_queue(), update_realtime_members(), and users_data_provider_get().

00814 {
00815    struct ao2_iterator a = {
00816       .c = c,
00817       .flags = flags
00818    };
00819 
00820    ao2_ref(c, +1);
00821    
00822    return a;
00823 }

int ao2_match_by_addr ( void *  user_data,
void *  arg,
int  flags 
)

another convenience function is a callback that matches on address

Definition at line 540 of file astobj2.c.

References CMP_MATCH, and CMP_STOP.

00541 {
00542    return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
00543 }

void* ao2_object_get_lockaddr ( void *  obj  ) 

Return the lock address of an object.

Parameters:
[in] obj A pointer to the object we want.
Returns:
the address of the lock, else NULL.

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.

Since:
1.6.1

Definition at line 202 of file astobj2.c.

References INTERNAL_OBJ(), __priv_data::lock, and astobj2::priv_data.

00203 {
00204    struct astobj2 *p = INTERNAL_OBJ(obj);
00205    
00206    if (p == NULL)
00207       return NULL;
00208 
00209    return &p->priv_data.lock;
00210 }

int astobj2_init ( void   ) 

Provided by astobj2.c

Definition at line 1132 of file astobj2.c.

References ARRAY_LEN, and ast_cli_register_multiple().

Referenced by main().

01133 {
01134 #ifdef AO2_DEBUG
01135    ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
01136 #endif
01137 
01138    return 0;
01139 }

static int cb_true ( void *  user_data,
void *  arg,
int  flags 
) [static]

special callback that matches all

Definition at line 573 of file astobj2.c.

References CMP_MATCH.

Referenced by internal_ao2_callback().

00574 {
00575    return CMP_MATCH;
00576 }

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 581 of file astobj2.c.

References CMP_MATCH.

Referenced by internal_ao2_callback().

00582 {
00583    return CMP_MATCH;
00584 }

static int cd_cb ( void *  obj,
void *  arg,
int  flag 
) [static]

Definition at line 947 of file astobj2.c.

References __ao2_ref().

Referenced by container_destruct().

00948 {
00949    __ao2_ref(obj, -1);
00950    return 0;
00951 }

static int cd_cb_debug ( void *  obj,
void *  arg,
int  flag 
) [static]

Definition at line 953 of file astobj2.c.

References __ao2_ref_debug().

Referenced by container_destruct_debug().

00954 {
00955    __ao2_ref_debug(obj, -1, "deref object via container destroy",  __FILE__, __LINE__, __PRETTY_FUNCTION__);
00956    return 0;
00957 }

static void container_destruct ( void *  c  )  [static]

Definition at line 959 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().

00960 {
00961    struct ao2_container *c = _c;
00962    int i;
00963 
00964    __ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
00965 
00966    for (i = 0; i < c->n_buckets; i++) {
00967       struct bucket_entry *current;
00968 
00969       while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
00970          ast_free(current);
00971       }
00972    }
00973 
00974 #ifdef AO2_DEBUG
00975    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00976 #endif
00977 }

static void container_destruct_debug ( void *  c  )  [static]

Definition at line 979 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().

00980 {
00981    struct ao2_container *c = _c;
00982    int i;
00983 
00984    __ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
00985 
00986    for (i = 0; i < c->n_buckets; i++) {
00987       struct bucket_entry *current;
00988 
00989       while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
00990          ast_free(current);
00991       }
00992    }
00993 
00994 #ifdef AO2_DEBUG
00995    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00996 #endif
00997 }

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.

Returns:
0

Definition at line 407 of file astobj2.c.

Referenced by internal_ao2_container_alloc().

00408 {
00409    return 0;
00410 }

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 296 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().

00297 {
00298    /* allocation */
00299    struct astobj2 *obj;
00300 
00301    if (data_size < sizeof(void *))
00302       data_size = sizeof(void *);
00303 
00304 #if defined(__AST_DEBUG_MALLOC)
00305    obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, funcname);
00306 #else
00307    obj = ast_calloc(1, sizeof(*obj) + data_size);
00308 #endif
00309 
00310    if (obj == NULL)
00311       return NULL;
00312 
00313    ast_mutex_init(&obj->priv_data.lock);
00314    obj->priv_data.magic = AO2_MAGIC;
00315    obj->priv_data.data_size = data_size;
00316    obj->priv_data.ref_counter = 1;
00317    obj->priv_data.destructor_fn = destructor_fn;   /* can be NULL */
00318 
00319 #ifdef AO2_DEBUG
00320    ast_atomic_fetchadd_int(&ao2.total_objects, 1);
00321    ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
00322    ast_atomic_fetchadd_int(&ao2.total_refs, 1);
00323 #endif
00324 
00325    /* return a pointer to the user data */
00326    return EXTERNAL_OBJ(obj);
00327 }

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.

Returns:
Is a pointer to an object or to a list of object if OBJ_MULTIPLE is specified. Luckily, for debug purposes, the added args (tag, file, line, funcname) aren't an excessive load to the system, as the callback should not be called as often as, say, the ao2_ref func is called.

Definition at line 594 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, 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().

00597 {
00598    int i, start, last;  /* search boundaries */
00599    void *ret = NULL;
00600    ao2_callback_fn *cb_default = NULL;
00601    ao2_callback_data_fn *cb_withdata = NULL;
00602    struct ao2_container *multi_container = NULL;
00603    struct ao2_iterator *multi_iterator = NULL;
00604 
00605    if (INTERNAL_OBJ(c) == NULL)  /* safety check on the argument */
00606       return NULL;
00607 
00608    /*
00609     * This logic is used so we can support OBJ_MULTIPLE with OBJ_NODATA
00610     * turned off.  This if statement checks for the special condition
00611     * where multiple items may need to be returned.
00612     */
00613    if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
00614       /* we need to return an ao2_iterator with the results,
00615        * as there could be more than one. the iterator will
00616        * hold the only reference to a container that has all the
00617        * matching objects linked into it, so when the iterator
00618        * is destroyed, the container will be automatically
00619        * destroyed as well.
00620        */
00621       if (!(multi_container = __ao2_container_alloc(1, NULL, NULL))) {
00622          return NULL;
00623       }
00624       if (!(multi_iterator = ast_calloc(1, sizeof(*multi_iterator)))) {
00625          ao2_ref(multi_container, -1);
00626          return NULL;
00627       }
00628    }
00629 
00630    /* override the match function if necessary */
00631    if (cb_fn == NULL) { /* if NULL, match everything */
00632       if (type == WITH_DATA) {
00633          cb_withdata = cb_true_data;
00634       } else {
00635          cb_default = cb_true;
00636       }
00637    } else {
00638       /* We do this here to avoid the per object casting penalty (even though
00639          that is probably optimized away anyway). */
00640       if (type == WITH_DATA) {
00641          cb_withdata = cb_fn;
00642       } else {
00643          cb_default = cb_fn;
00644       }
00645    }
00646 
00647    /*
00648     * XXX this can be optimized.
00649     * If we have a hash function and lookup by pointer,
00650     * run the hash function. Otherwise, scan the whole container
00651     * (this only for the time being. We need to optimize this.)
00652     */
00653    if ((flags & OBJ_POINTER)) /* we know hash can handle this case */
00654       start = i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets;
00655    else        /* don't know, let's scan all buckets */
00656       start = i = -1;      /* XXX this must be fixed later. */
00657 
00658    /* determine the search boundaries: i..last-1 */
00659    if (i < 0) {
00660       start = i = 0;
00661       last = c->n_buckets;
00662    } else if ((flags & OBJ_CONTINUE)) {
00663       last = c->n_buckets;
00664    } else {
00665       last = i + 1;
00666    }
00667 
00668    ao2_lock(c);   /* avoid modifications to the content */
00669 
00670    for (; i < last ; i++) {
00671       /* scan the list with prev-cur pointers */
00672       struct bucket_entry *cur;
00673 
00674       AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) {
00675          int match = (CMP_MATCH | CMP_STOP);
00676 
00677          if (type == WITH_DATA) {
00678             match &= cb_withdata(EXTERNAL_OBJ(cur->astobj), arg, data, flags);
00679          } else {
00680             match &= cb_default(EXTERNAL_OBJ(cur->astobj), arg, flags);
00681          }
00682 
00683          /* we found the object, performing operations according flags */
00684          if (match == 0) { /* no match, no stop, continue */
00685             continue;
00686          } else if (match == CMP_STOP) {  /* no match but stop, we are done */
00687             i = last;
00688             break;
00689          }
00690 
00691          /* we have a match (CMP_MATCH) here */
00692          if (!(flags & OBJ_NODATA)) {  /* if must return the object, record the value */
00693             /* it is important to handle this case before the unlink */
00694             ret = EXTERNAL_OBJ(cur->astobj);
00695             if (!(flags & (OBJ_UNLINK | OBJ_MULTIPLE))) {
00696                if (tag)
00697                   __ao2_ref_debug(ret, 1, tag, file, line, funcname);
00698                else
00699                   __ao2_ref(ret, 1);
00700             }
00701          }
00702 
00703          /* If we are in OBJ_MULTIPLE mode and OBJ_NODATE is off, 
00704           * link the object into the container that will hold the results.
00705           */
00706          if (ret && (multi_container != NULL)) {
00707             if (tag) {
00708                __ao2_link_debug(multi_container, ret, tag, file, line, funcname);
00709             } else {
00710                __ao2_link(multi_container, ret);
00711             }
00712             ret = NULL;
00713          }
00714 
00715          if (flags & OBJ_UNLINK) {  /* must unlink */
00716             /* we are going to modify the container, so update version */
00717             ast_atomic_fetchadd_int(&c->version, 1);
00718             AST_LIST_REMOVE_CURRENT(entry);
00719             /* update number of elements */
00720             ast_atomic_fetchadd_int(&c->elements, -1);
00721 
00722             /* - When unlinking and not returning the result, (OBJ_NODATA), the ref from the container
00723              * must be decremented.
00724              * - When unlinking with OBJ_MULTIPLE the ref from the original container
00725              * must be decremented regardless if OBJ_NODATA is used. This is because the result is
00726              * returned in a new container that already holds its own ref for the object. If the ref
00727              * from the original container is not accounted for here a memory leak occurs. */
00728             if (flags & (OBJ_NODATA | OBJ_MULTIPLE)) {
00729                if (tag)
00730                   __ao2_ref_debug(EXTERNAL_OBJ(cur->astobj), -1, tag, file, line, funcname);
00731                else
00732                   __ao2_ref(EXTERNAL_OBJ(cur->astobj), -1);
00733             }
00734             ast_free(cur); /* free the link record */
00735          }
00736 
00737          if ((match & CMP_STOP) || !(flags & OBJ_MULTIPLE)) {
00738             /* We found our only (or last) match, so force an exit from
00739                the outside loop. */
00740             i = last;
00741             break;
00742          }
00743       }
00744       AST_LIST_TRAVERSE_SAFE_END;
00745 
00746       if (ret) {
00747          break;
00748       }
00749 
00750       if (i == c->n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) {
00751          /* Move to the beginning to ensure we check every bucket */
00752          i = -1;
00753          last = start;
00754       }
00755    }
00756    ao2_unlock(c);
00757 
00758    /* if multi_container was created, we are returning multiple objects */
00759    if (multi_container != NULL) {
00760       *multi_iterator = ao2_iterator_init(multi_container,
00761                       AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK | AO2_ITERATOR_MALLOCD);
00762       ao2_ref(multi_container, -1);
00763       return multi_iterator;
00764    } else {
00765       return ret;
00766    }
00767 }

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 415 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.

00417 {
00418    /* XXX maybe consistency check on arguments ? */
00419    /* compute the container size */
00420 
00421    if (!c)
00422       return NULL;
00423    
00424    c->version = 1;   /* 0 is a reserved value here */
00425    c->n_buckets = hash_fn ? n_buckets : 1;
00426    c->hash_fn = hash_fn ? hash_fn : hash_zero;
00427    c->cmp_fn = cmp_fn;
00428 
00429 #ifdef AO2_DEBUG
00430    ast_atomic_fetchadd_int(&ao2.total_containers, 1);
00431 #endif
00432 
00433    return c;
00434 }

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]
static void * internal_ao2_iterator_next ( struct ao2_iterator a,
struct bucket_entry **  q 
) [static]

Definition at line 841 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().

00842 {
00843    int lim;
00844    struct bucket_entry *p = NULL;
00845    void *ret = NULL;
00846 
00847    *q = NULL;
00848    
00849    if (INTERNAL_OBJ(a->c) == NULL)
00850       return NULL;
00851 
00852    if (!(a->flags & AO2_ITERATOR_DONTLOCK))
00853       ao2_lock(a->c);
00854 
00855    /* optimization. If the container is unchanged and
00856     * we have a pointer, try follow it
00857     */
00858    if (a->c->version == a->c_version && (p = a->obj)) {
00859       if ((p = AST_LIST_NEXT(p, entry)))
00860          goto found;
00861       /* nope, start from the next bucket */
00862       a->bucket++;
00863       a->version = 0;
00864       a->obj = NULL;
00865    }
00866 
00867    lim = a->c->n_buckets;
00868 
00869    /* Browse the buckets array, moving to the next
00870     * buckets if we don't find the entry in the current one.
00871     * Stop when we find an element with version number greater
00872     * than the current one (we reset the version to 0 when we
00873     * switch buckets).
00874     */
00875    for (; a->bucket < lim; a->bucket++, a->version = 0) {
00876       /* scan the current bucket */
00877       AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) {
00878          if (p->version > a->version)
00879             goto found;
00880       }
00881    }
00882 
00883 found:
00884    if (p) {
00885       ret = EXTERNAL_OBJ(p->astobj);
00886       if (a->flags & AO2_ITERATOR_UNLINK) {
00887          /* we are going to modify the container, so update version */
00888          ast_atomic_fetchadd_int(&a->c->version, 1);
00889          AST_LIST_REMOVE(&a->c->buckets[a->bucket], p, entry);
00890          /* update number of elements */
00891          ast_atomic_fetchadd_int(&a->c->elements, -1);
00892          a->version = 0;
00893          a->obj = NULL;
00894          a->c_version = a->c->version;
00895          ast_free(p);
00896       } else {
00897          a->version = p->version;
00898          a->obj = p;
00899          a->c_version = a->c->version;
00900          /* inc refcount of returned object */
00901          *q = p;
00902       }
00903    }
00904 
00905    return ret;
00906 }

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 485 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().

00486 {
00487    int i;
00488    /* create a new list entry */
00489    struct bucket_entry *p;
00490    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00491 
00492    if (obj == NULL)
00493       return NULL;
00494 
00495    if (INTERNAL_OBJ(c) == NULL)
00496       return NULL;
00497 
00498    p = ast_calloc(1, sizeof(*p));
00499    if (!p)
00500       return NULL;
00501 
00502    i = abs(c->hash_fn(user_data, OBJ_POINTER));
00503 
00504    ao2_lock(c);
00505    i %= c->n_buckets;
00506    p->astobj = obj;
00507    p->version = ast_atomic_fetchadd_int(&c->version, 1);
00508    AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
00509    ast_atomic_fetchadd_int(&c->elements, 1);
00510 
00511    /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
00512    return p;
00513 }

static int internal_ao2_ref ( void *  user_data,
const int  delta 
) [static]

Definition at line 247 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().

00248 {
00249    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00250    int current_value;
00251    int ret;
00252 
00253    if (obj == NULL)
00254       return -1;
00255 
00256    /* if delta is 0, just return the refcount */
00257    if (delta == 0)
00258       return (obj->priv_data.ref_counter);
00259 
00260    /* we modify with an atomic operation the reference counter */
00261    ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
00262    current_value = ret + delta;
00263 
00264 #ifdef AO2_DEBUG  
00265    ast_atomic_fetchadd_int(&ao2.total_refs, delta);
00266 #endif
00267 
00268    /* this case must never happen */
00269    if (current_value < 0)
00270       ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data);
00271 
00272    if (current_value <= 0) { /* last reference, destroy the object */
00273       if (obj->priv_data.destructor_fn != NULL) {
00274          obj->priv_data.destructor_fn(user_data);
00275       }
00276 
00277       ast_mutex_destroy(&obj->priv_data.lock);
00278 #ifdef AO2_DEBUG
00279       ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
00280       ast_atomic_fetchadd_int(&ao2.total_objects, -1);
00281 #endif
00282       /* for safety, zero-out the astobj2 header and also the
00283        * first word of the user-data, which we make sure is always
00284        * allocated. */
00285       memset(obj, '\0', sizeof(struct astobj2 *) + sizeof(void *) );
00286       ast_free(obj);
00287    }
00288 
00289    return ret;
00290 }

static struct astobj2* INTERNAL_OBJ ( void *  user_data  )  [static, read]

convert from a pointer _p to a user-defined object

Returns:
the pointer to the astobj2 structure

Definition at line 110 of file astobj2.c.

References AO2_MAGIC, 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().

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       if (p->priv_data.magic) {
00122          ast_log(LOG_ERROR, "bad magic number 0x%x for object %p\n",
00123             p->priv_data.magic, user_data);
00124       } else {
00125          ast_log(LOG_ERROR,
00126             "bad magic number for object %p. Object is likely destroyed.\n",
00127             user_data);
00128       }
00129       return NULL;
00130    }
00131 
00132    return p;
00133 }


Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1