Wed Apr 6 11:29:53 2011

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)
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_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 51 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 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"

Definition at line 28 of file astobj2.c.

Referenced by __ao2_alloc_debug(), and __ao2_ref_debug().


Enumeration Type Documentation

enum ao2_callback_type

Enumerator:
DEFAULT 
WITH_DATA 

Definition at line 123 of file astobj2.c.

00123                        {
00124    DEFAULT,
00125    WITH_DATA,
00126 };


Function Documentation

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.

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

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

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

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.

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

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 
)

another convenience function is a callback that matches on address

Definition at line 529 of file astobj2.c.

References CMP_MATCH, and CMP_STOP.

00530 {
00531    return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
00532 }

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

Returns:
0

Definition at line 396 of file astobj2.c.

Referenced by internal_ao2_container_alloc().

00397 {
00398    return 0;
00399 }

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.

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

Returns:
the pointer to the astobj2 structure

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 }


Generated on Wed Apr 6 11:29:53 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7