Thu Oct 8 21:56:11 2009

Asterisk developer's documentation


astobj2.c File Reference

#include "asterisk.h"
#include "asterisk/astobj2.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"

Include dependency graph for astobj2.c:

Go to the source code of this file.

Data Structures

struct  __priv_data
struct  ao2_container
struct  astobj2
struct  bucket_list

Defines

#define AO2_MAGIC   0xa570b123
#define EXTERNAL_OBJ(_p)   ((_p) == NULL ? NULL : (_p)->user_data)
 convert from a pointer _p to an astobj2 object

Functions

void * __ao2_link (struct ao2_container *c, void *user_data, int iax2_hack)
void * ao2_alloc (size_t data_size, ao2_destructor_fn destructor_fn)
void ao2_bt (void)
void * ao2_callback (struct ao2_container *c, const enum search_flags flags, ao2_callback_fn cb_fn, void *arg)
struct ao2_containerao2_container_alloc (const uint n_buckets, ao2_hash_fn hash_fn, ao2_callback_fn cmp_fn)
int ao2_container_count (struct ao2_container *c)
void * ao2_find (struct ao2_container *c, void *arg, enum search_flags flags)
struct ao2_iterator ao2_iterator_init (struct ao2_container *c, int flags)
void * ao2_iterator_next (struct ao2_iterator *a)
int ao2_lock (void *user_data)
int ao2_match_by_addr (void *user_data, void *arg, int flags)
 another convenience function is a callback that matches on address
int ao2_ref (void *user_data, const int delta)
void * ao2_unlink (struct ao2_container *c, void *user_data)
int ao2_unlock (void *user_data)
 AST_LIST_HEAD_NOLOCK (bucket, bucket_list)
int astobj2_init (void)
static int cb_true (void *user_data, void *arg, int flags)
 special callback that matches all
static int cd_cb (void *obj, void *arg, int flag)
static void container_destruct (void *c)
static int hash_zero (const void *user_obj, const int flags)
 always zero hash function
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 49 of file astobj2.c.

Referenced by 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 126 of file astobj2.c.

Referenced by ao2_alloc(), ao2_callback(), and ao2_iterator_next().


Function Documentation

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

Definition at line 340 of file astobj2.c.

References ao2_lock(), ao2_ref(), ao2_unlock(), ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, ao2_container::buckets, ao2_container::elements, ao2_container::hash_fn, INTERNAL_OBJ(), ao2_container::n_buckets, and ao2_container::version.

Referenced by set_config().

00341 {
00342    int i;
00343    /* create a new list entry */
00344    struct bucket_list *p;
00345    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00346    
00347    if (!obj)
00348       return NULL;
00349 
00350    if (INTERNAL_OBJ(c) == NULL)
00351       return NULL;
00352 
00353    p = ast_calloc(1, sizeof(*p));
00354    if (!p)
00355       return NULL;
00356 
00357    i = c->hash_fn(user_data, OBJ_POINTER);
00358 
00359    ao2_lock(c);
00360    i %= c->n_buckets;
00361    p->astobj = obj;
00362    p->version = ast_atomic_fetchadd_int(&c->version, 1);
00363    if (iax2_hack)
00364       AST_LIST_INSERT_HEAD(&c->buckets[i], p, entry);
00365    else
00366       AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
00367    ast_atomic_fetchadd_int(&c->elements, 1);
00368    ao2_ref(user_data, +1);
00369    ao2_unlock(c);
00370    
00371    return p;
00372 }

void* ao2_alloc ( size_t  data_size,
ao2_destructor_fn  destructor_fn 
)

Definition at line 207 of file astobj2.c.

References AO2_MAGIC, 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_container_alloc(), build_peer(), build_user(), create_queue_member(), new_iax(), and xml_translate().

00208 {
00209    /* allocation */
00210    struct astobj2 *obj;
00211 
00212    if (data_size < sizeof(void *))
00213       data_size = sizeof(void *);
00214 
00215    obj = ast_calloc(1, sizeof(*obj) + data_size);
00216 
00217    if (obj == NULL)
00218       return NULL;
00219 
00220    ast_mutex_init(&obj->priv_data.lock);
00221    obj->priv_data.magic = AO2_MAGIC;
00222    obj->priv_data.data_size = data_size;
00223    obj->priv_data.ref_counter = 1;
00224    obj->priv_data.destructor_fn = destructor_fn;   /* can be NULL */
00225 
00226 #ifdef AO2_DEBUG
00227    ast_atomic_fetchadd_int(&ao2.total_objects, 1);
00228    ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
00229    ast_atomic_fetchadd_int(&ao2.total_refs, 1);
00230 #endif
00231 
00232    /* return a pointer to the user data */
00233    return EXTERNAL_OBJ(obj);
00234 }

void ao2_bt ( void   ) 

Definition at line 77 of file astobj2.c.

00077 {}

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

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.

Definition at line 409 of file astobj2.c.

References ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ast_log(), ao2_container::buckets, cb_true(), ao2_container::elements, EXTERNAL_OBJ, free, ao2_container::hash_fn, INTERNAL_OBJ(), last, LOG_WARNING, match(), ao2_container::n_buckets, and ao2_container::version.

Referenced by ao2_find(), ao2_unlink(), container_destruct(), delete_users(), and load_module().

00412 {
00413    int i, last;   /* search boundaries */
00414    void *ret = NULL;
00415 
00416    if (INTERNAL_OBJ(c) == NULL)  /* safety check on the argument */
00417       return NULL;
00418 
00419    if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
00420       ast_log(LOG_WARNING, "multiple data return not implemented yet (flags %x)\n", flags);
00421       return NULL;
00422    }
00423 
00424    /* override the match function if necessary */
00425 #if 0
00426    /* Removing this slightly changes the meaning of OBJ_POINTER, but makes it
00427     * do what I want it to.  I'd like to hint to ao2_callback that the arg is
00428     * of the same object type, so it can be passed to the hash function.
00429     * However, I don't want to imply that this is the object being searched for. */
00430    if (flags & OBJ_POINTER)
00431       cb_fn = match_by_addr;
00432    else
00433 #endif
00434    if (cb_fn == NULL)   /* if NULL, match everything */
00435       cb_fn = cb_true;
00436    /*
00437     * XXX this can be optimized.
00438     * If we have a hash function and lookup by pointer,
00439     * run the hash function. Otherwise, scan the whole container
00440     * (this only for the time being. We need to optimize this.)
00441     */
00442    if ((flags & OBJ_POINTER)) /* we know hash can handle this case */
00443       i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets;
00444    else        /* don't know, let's scan all buckets */
00445       i = -1;     /* XXX this must be fixed later. */
00446 
00447    /* determine the search boundaries: i..last-1 */
00448    if (i < 0) {
00449       i = 0;
00450       last = c->n_buckets;
00451    } else {
00452       last = i + 1;
00453    }
00454 
00455    ao2_lock(c);   /* avoid modifications to the content */
00456 
00457    for (; i < last ; i++) {
00458       /* scan the list with prev-cur pointers */
00459       struct bucket_list *cur;
00460 
00461       AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) {
00462          int match = cb_fn(EXTERNAL_OBJ(cur->astobj), arg, flags) & (CMP_MATCH | CMP_STOP);
00463 
00464          /* we found the object, performing operations according flags */
00465          if (match == 0) { /* no match, no stop, continue */
00466             continue;
00467          } else if (match == CMP_STOP) {  /* no match but stop, we are done */
00468             i = last;
00469             break;
00470          }
00471          /* we have a match (CMP_MATCH) here */
00472          if (!(flags & OBJ_NODATA)) {  /* if must return the object, record the value */
00473             /* it is important to handle this case before the unlink */
00474             ret = EXTERNAL_OBJ(cur->astobj);
00475             ao2_ref(ret, 1);
00476          }
00477 
00478          if (flags & OBJ_UNLINK) {  /* must unlink */
00479             struct bucket_list *x = cur;
00480 
00481             /* we are going to modify the container, so update version */
00482             ast_atomic_fetchadd_int(&c->version, 1);
00483             AST_LIST_REMOVE_CURRENT(&c->buckets[i], entry);
00484             /* update number of elements and version */
00485             ast_atomic_fetchadd_int(&c->elements, -1);
00486             ao2_ref(EXTERNAL_OBJ(x->astobj), -1);
00487             free(x); /* free the link record */
00488          }
00489 
00490          if ((match & CMP_STOP) || (flags & OBJ_MULTIPLE) == 0) {
00491             /* We found the only match we need */
00492             i = last;   /* force exit from outer loop */
00493             break;
00494          }
00495          if (!(flags & OBJ_NODATA)) {
00496 #if 0 /* XXX to be completed */
00497             /*
00498              * This is the multiple-return case. We need to link
00499              * the object in a list. The refcount is already increased.
00500              */
00501 #endif
00502          }
00503       }
00504       AST_LIST_TRAVERSE_SAFE_END
00505    }
00506    ao2_unlock(c);
00507    return ret;
00508 }

struct ao2_container* ao2_container_alloc ( const uint  n_buckets,
ao2_hash_fn  hash_fn,
ao2_callback_fn  cmp_fn 
) [read]

Definition at line 294 of file astobj2.c.

References ao2_alloc(), ao2_container::cmp_fn, container_destruct(), ao2_container::hash_fn, hash_zero(), ao2_container::n_buckets, and ao2_container::version.

Referenced by init_queue(), load_module(), and xml_translate().

00296 {
00297    /* XXX maybe consistency check on arguments ? */
00298    /* compute the container size */
00299    size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
00300 
00301    struct ao2_container *c = ao2_alloc(container_size, container_destruct);
00302 
00303    if (!c)
00304       return NULL;
00305    
00306    c->version = 1;   /* 0 is a reserved value here */
00307    c->n_buckets = n_buckets;
00308    c->hash_fn = hash_fn ? hash_fn : hash_zero;
00309    c->cmp_fn = cmp_fn;
00310 
00311 #ifdef AO2_DEBUG
00312    ast_atomic_fetchadd_int(&ao2.total_containers, 1);
00313 #endif
00314 
00315    return c;
00316 }

int ao2_container_count ( struct ao2_container c  ) 

return the number of elements in the container

Definition at line 321 of file astobj2.c.

References ao2_container::elements.

Referenced by __queues_show().

00322 {
00323    return c->elements;
00324 }

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

the find function just invokes the default callback with some reasonable flags.

Definition at line 513 of file astobj2.c.

References ao2_callback(), and ao2_container::cmp_fn.

Referenced by __find_callno(), authenticate_request(), authenticate_verify(), build_peer(), build_user(), compare_weight(), find_peer(), iax2_destroy_helper(), interface_exists_global(), reload_queues(), remove_from_queue(), rt_handle_member_record(), and xml_translate().

00514 {
00515    return ao2_callback(c, flags, c->cmp_fn, arg);
00516 }

struct ao2_iterator ao2_iterator_init ( struct ao2_container c,
int  flags 
) [read]

void* ao2_iterator_next ( struct ao2_iterator a  ) 

Definition at line 534 of file astobj2.c.

References ao2_lock(), ao2_ref(), ao2_unlock(), AST_LIST_NEXT, AST_LIST_TRAVERSE, ao2_iterator::bucket, ao2_container::buckets, ao2_iterator::c, ao2_iterator::c_version, EXTERNAL_OBJ, F_AO2I_DONTLOCK, ao2_iterator::flags, INTERNAL_OBJ(), ao2_container::n_buckets, ao2_iterator::obj, ao2_iterator::version, and ao2_container::version.

Referenced by __iax2_show_peers(), __queues_show(), authenticate_reply(), check_access(), complete_iax2_show_peer(), complete_queue_remove_member(), dump_queue_members(), find_queue_by_name_rt(), free_members(), get_member_status(), iax2_getpeername(), iax2_getpeertrunk(), iax2_show_users(), interface_exists(), is_our_turn(), manager_queues_status(), poke_all_peers(), prune_peers(), prune_users(), queue_function_qac(), queue_function_queuememberlist(), reload_queues(), try_calling(), update_realtime_members(), and update_status().

00535 {
00536    int lim;
00537    struct bucket_list *p = NULL;
00538    void *ret = NULL;
00539 
00540    if (INTERNAL_OBJ(a->c) == NULL)
00541       return NULL;
00542 
00543    if (!(a->flags & F_AO2I_DONTLOCK))
00544       ao2_lock(a->c);
00545 
00546    /* optimization. If the container is unchanged and
00547     * we have a pointer, try follow it
00548     */
00549    if (a->c->version == a->c_version && (p = a->obj) ) {
00550       if ( (p = AST_LIST_NEXT(p, entry)) )
00551          goto found;
00552       /* nope, start from the next bucket */
00553       a->bucket++;
00554       a->version = 0;
00555       a->obj = NULL;
00556    }
00557 
00558    lim = a->c->n_buckets;
00559 
00560    /* Browse the buckets array, moving to the next
00561     * buckets if we don't find the entry in the current one.
00562     * Stop when we find an element with version number greater
00563     * than the current one (we reset the version to 0 when we
00564     * switch buckets).
00565     */
00566    for (; a->bucket < lim; a->bucket++, a->version = 0) {
00567       /* scan the current bucket */
00568       AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) {
00569          if (p->version > a->version)
00570             goto found;
00571       }
00572    }
00573 
00574 found:
00575    if (p) {
00576       a->version = p->version;
00577       a->obj = p;
00578       a->c_version = a->c->version;
00579       ret = EXTERNAL_OBJ(p->astobj);
00580       /* inc refcount of returned object */
00581       ao2_ref(ret, 1);
00582    }
00583 
00584    if (!(a->flags & F_AO2I_DONTLOCK))
00585       ao2_unlock(a->c);
00586 
00587    return ret;
00588 }

int ao2_lock ( void *  user_data  ) 

Definition at line 128 of file astobj2.c.

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

Referenced by __ao2_link(), ao2_callback(), and ao2_iterator_next().

00129 {
00130    struct astobj2 *p = INTERNAL_OBJ(user_data);
00131 
00132    if (p == NULL)
00133       return -1;
00134 
00135 #ifdef AO2_DEBUG
00136    ast_atomic_fetchadd_int(&ao2.total_locked, 1);
00137 #endif
00138 
00139    return ast_mutex_lock(&p->priv_data.lock);
00140 }

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

Referenced by ao2_unlink().

00378 {
00379    return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
00380 }

int ao2_ref ( void *  user_data,
const int  delta 
)

Definition at line 159 of file astobj2.c.

References ast_log(), ast_mutex_destroy(), __priv_data::data_size, __priv_data::destructor_fn, free, INTERNAL_OBJ(), __priv_data::lock, LOG_ERROR, astobj2::priv_data, and __priv_data::ref_counter.

Referenced by __ao2_link(), __find_callno(), __queues_show(), __unload_module(), add_to_queue(), ao2_callback(), ao2_iterator_next(), cd_cb(), compare_weight(), complete_queue_remove_member(), destroy_queue(), dump_queue_members(), find_queue_by_name_rt(), free_members(), get_member_status(), hangupcalls(), iax2_destroy(), interface_exists(), interface_exists_global(), is_our_turn(), load_module(), manager_queues_status(), new_iax(), peer_ref(), peer_unref(), queue_function_qac(), queue_function_queuememberlist(), reload_queues(), remove_from_queue(), rt_handle_member_record(), set_member_paused(), try_calling(), update_realtime_members(), update_status(), user_ref(), user_unref(), and xml_translate().

00160 {
00161    int current_value;
00162    int ret;
00163    struct astobj2 *obj = INTERNAL_OBJ(user_data);
00164 
00165    if (obj == NULL)
00166       return -1;
00167 
00168    /* if delta is 0, just return the refcount */
00169    if (delta == 0)
00170       return (obj->priv_data.ref_counter);
00171 
00172    /* we modify with an atomic operation the reference counter */
00173    ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
00174    current_value = ret + delta;
00175 
00176 #ifdef AO2_DEBUG  
00177    ast_atomic_fetchadd_int(&ao2.total_refs, delta);
00178 #endif
00179 
00180    /* this case must never happen */
00181    if (current_value < 0)
00182       ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data);
00183 
00184    if (current_value <= 0) { /* last reference, destroy the object */
00185       if (obj->priv_data.destructor_fn != NULL) 
00186          obj->priv_data.destructor_fn(user_data);
00187 
00188       ast_mutex_destroy(&obj->priv_data.lock);
00189 #ifdef AO2_DEBUG
00190       ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
00191       ast_atomic_fetchadd_int(&ao2.total_objects, -1);
00192 #endif
00193       /* for safety, zero-out the astobj2 header and also the
00194        * first word of the user-data, which we make sure is always
00195        * allocated. */
00196       bzero(obj, sizeof(struct astobj2 *) + sizeof(void *) );
00197       free(obj);
00198    }
00199 
00200    return ret;
00201 }

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

Definition at line 386 of file astobj2.c.

References ao2_callback(), ao2_match_by_addr(), and INTERNAL_OBJ().

Referenced by build_user(), find_queue_by_name_rt(), free_members(), prune_users(), reload_queues(), remove_by_peercallno(), remove_from_queue(), unlink_peer(), and update_realtime_members().

00387 {
00388    if (INTERNAL_OBJ(user_data) == NULL)   /* safety check on the argument */
00389       return NULL;
00390 
00391    ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data);
00392 
00393    return NULL;
00394 }

int ao2_unlock ( void *  user_data  ) 

Definition at line 142 of file astobj2.c.

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

Referenced by __ao2_link(), ao2_callback(), and ao2_iterator_next().

00143 {
00144    struct astobj2 *p = INTERNAL_OBJ(user_data);
00145 
00146    if (p == NULL)
00147       return -1;
00148 
00149 #ifdef AO2_DEBUG
00150    ast_atomic_fetchadd_int(&ao2.total_locked, -1);
00151 #endif
00152 
00153    return ast_mutex_unlock(&p->priv_data.lock);
00154 }

AST_LIST_HEAD_NOLOCK ( bucket  ,
bucket_list   
)

int astobj2_init ( void   ) 

Definition at line 712 of file astobj2.c.

References ARRAY_LEN, and ast_cli_register_multiple().

Referenced by main().

00713 {
00714 #ifdef AO2_DEBUG
00715    ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
00716 #endif
00717 
00718    return 0;
00719 }

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

special callback that matches all

Definition at line 399 of file astobj2.c.

Referenced by ao2_callback().

00400 {
00401    return CMP_MATCH;
00402 }

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

Definition at line 593 of file astobj2.c.

References ao2_ref().

Referenced by container_destruct().

00594 {
00595    ao2_ref(obj, -1);
00596    return 0;
00597 }

static void container_destruct ( void *  c  )  [static]

Definition at line 599 of file astobj2.c.

References ao2_callback(), and cd_cb().

Referenced by ao2_container_alloc().

00600 {
00601    struct ao2_container *c = _c;
00602 
00603    ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
00604 
00605 #ifdef AO2_DEBUG
00606    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00607 #endif
00608 }

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

Referenced by ao2_container_alloc().

00286 {
00287    return 0;
00288 }

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

References AO2_MAGIC, ast_log(), LOG_ERROR, __priv_data::magic, and astobj2::priv_data.

Referenced by __ao2_link(), ao2_callback(), ao2_iterator_next(), ao2_lock(), ao2_ref(), ao2_unlink(), and ao2_unlock().

00104 {
00105    struct astobj2 *p;
00106 
00107    if (!user_data) {
00108       ast_log(LOG_ERROR, "user_data is NULL\n");
00109       return NULL;
00110    }
00111 
00112    p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
00113    if (AO2_MAGIC != (p->priv_data.magic) ) {
00114       ast_log(LOG_ERROR, "bad magic number 0x%x for %p\n", p->priv_data.magic, p);
00115       p = NULL;
00116    }
00117 
00118    return p;
00119 }


Generated on Thu Oct 8 21:56:11 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6