Wed Oct 28 15:48:22 2009

Asterisk developer's documentation


astobj2.c File Reference

#include "asterisk.h"
#include <stdlib.h>
#include "asterisk/astobj2.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/linkedlists.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 unsigned int 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 52 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 129 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 343 of file astobj2.c.

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

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

void* ao2_alloc ( size_t  data_size,
ao2_destructor_fn  destructor_fn 
)

Definition at line 210 of file astobj2.c.

References AO2_MAGIC, ast_mutex_init(), calloc, __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 add_calltoken_ignore(), ao2_container_alloc(), build_callno_limits(), create_callno_pools(), new_iax(), and peercnt_add().

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

void ao2_bt ( void   ) 

Definition at line 80 of file astobj2.c.

00080 {}

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 412 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(), calltoken_required(), container_destruct(), and set_peercnt_limit().

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

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 297 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 create_callno_pools(), and load_objects().

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

int ao2_container_count ( struct ao2_container c  ) 

return the number of elements in the container

Definition at line 324 of file astobj2.c.

References ao2_container::elements.

Referenced by get_unused_callno().

00325 {
00326    return c->elements;
00327 }

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

References ao2_callback(), and ao2_container::cmp_fn.

Referenced by add_calltoken_ignore(), build_callno_limits(), find_callno(), get_unused_callno(), peercnt_add(), peercnt_modify(), peercnt_remove_by_addr(), and sched_delay_remove().

00530 {
00531    return ao2_callback(c, flags, c->cmp_fn, arg);
00532 }

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

initialize an iterator so we start from the first object

Definition at line 537 of file astobj2.c.

References ao2_iterator::c, and ao2_iterator::flags.

Referenced by iax2_show_callnumber_usage().

00538 {
00539    struct ao2_iterator a = {
00540       .c = c,
00541       .flags = flags
00542    };
00543    
00544    return a;
00545 }

void* ao2_iterator_next ( struct ao2_iterator a  ) 

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

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

int ao2_lock ( void *  user_data  ) 

Definition at line 131 of file astobj2.c.

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

Referenced by __ao2_link(), add_calltoken_ignore(), ao2_callback(), ao2_iterator_next(), build_callno_limits(), get_unused_callno(), peercnt_add(), peercnt_remove(), and replace_callno().

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

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

Referenced by ao2_unlink().

00381 {
00382    return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
00383 }

int ao2_ref ( void *  user_data,
const int  delta 
)

Definition at line 162 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(), __unload_module(), add_calltoken_ignore(), ao2_callback(), ao2_iterator_next(), build_callno_limits(), calltoken_required(), cd_cb(), create_callno_pools(), find_callno(), iax2_destroy(), iax2_show_callnumber_usage(), load_objects(), peercnt_add(), peercnt_modify(), peercnt_remove_by_addr(), peercnt_remove_cb(), replace_callno(), sched_delay_remove(), and set_peercnt_limit().

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

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

Definition at line 389 of file astobj2.c.

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

Referenced by peercnt_remove(), and remove_by_peercallno().

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

int ao2_unlock ( void *  user_data  ) 

Definition at line 145 of file astobj2.c.

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

Referenced by __ao2_link(), add_calltoken_ignore(), ao2_callback(), ao2_iterator_next(), build_callno_limits(), get_unused_callno(), peercnt_add(), peercnt_remove(), and replace_callno().

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

AST_LIST_HEAD_NOLOCK ( bucket  ,
bucket_list   
)

int astobj2_init ( void   ) 

Definition at line 728 of file astobj2.c.

References ast_cli_register_multiple().

00729 {
00730 #ifdef AO2_DEBUG
00731    ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
00732 #endif
00733 
00734    return 0;
00735 }

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

special callback that matches all

Definition at line 402 of file astobj2.c.

Referenced by ao2_callback().

00403 {
00404    return CMP_MATCH;
00405 }

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

Definition at line 609 of file astobj2.c.

References ao2_ref().

Referenced by container_destruct().

00610 {
00611    ao2_ref(obj, -1);
00612    return 0;
00613 }

static void container_destruct ( void *  c  )  [static]

Definition at line 615 of file astobj2.c.

References ao2_callback(), and cd_cb().

Referenced by ao2_container_alloc().

00616 {
00617    struct ao2_container *c = _c;
00618 
00619    ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
00620 
00621 #ifdef AO2_DEBUG
00622    ast_atomic_fetchadd_int(&ao2.total_containers, -1);
00623 #endif
00624 }

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

Referenced by ao2_container_alloc().

00289 {
00290    return 0;
00291 }

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

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


Generated on Wed Oct 28 15:48:22 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6