#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) |
ao2_container * | ao2_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) |
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 astobj2 * | INTERNAL_OBJ (void *user_data) |
convert from a pointer _p to a user-defined object |
#define AO2_MAGIC 0xa570b123 |
#define EXTERNAL_OBJ | ( | _p | ) | ((_p) == NULL ? NULL : (_p)->user_data) |
convert from a pointer _p to an astobj2 object
Definition at line 126 of file astobj2.c.
Referenced by ao2_alloc(), and ao2_callback().
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(), and EXTERNAL_OBJ.
Referenced by ao2_container_alloc(), build_peer(), build_user(), create_queue_member(), 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_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.
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 | |||
) |
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 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 | |||
) |
initialize an iterator so we start from the first object
Definition at line 521 of file astobj2.c.
References ao2_iterator::c, and ao2_iterator::flags.
Referenced by __iax2_show_peers(), __queues_show(), authenticate_reply(), check_access(), complete_iax2_show_peer(), complete_queue_remove_member(), dump_queue_members(), 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().
00522 { 00523 struct ao2_iterator a = { 00524 .c = c, 00525 .flags = flags 00526 }; 00527 00528 return a; 00529 }
void* ao2_iterator_next | ( | struct ao2_iterator * | a | ) |
Definition at line 534 of file astobj2.c.
References ao2_lock(), AST_LIST_NEXT, AST_LIST_TRAVERSE, ao2_iterator::bucket, ao2_container::buckets, ao2_iterator::c, ao2_iterator::c_version, F_AO2I_DONTLOCK, ao2_iterator::flags, INTERNAL_OBJ(), ao2_container::n_buckets, ao2_iterator::obj, ao2_container::version, and ao2_iterator::version.
Referenced by __iax2_show_peers(), __queues_show(), authenticate_reply(), check_access(), complete_iax2_show_peer(), complete_queue_remove_member(), dump_queue_members(), 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(), __queues_show(), __unload_module(), add_to_queue(), ao2_callback(), cd_cb(), compare_weight(), complete_queue_remove_member(), destroy_queue(), dump_queue_members(), free_members(), get_member_status(), hangupcalls(), interface_exists(), interface_exists_global(), is_our_turn(), load_module(), manager_queues_status(), 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(), free_members(), prune_users(), reload_queues(), 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(), and ao2_callback().
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().
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.
Definition at line 285 of file astobj2.c.
Referenced by ao2_container_alloc().
static struct astobj2* INTERNAL_OBJ | ( | void * | user_data | ) | [inline, static] |
convert from a pointer _p to a user-defined object
Definition at line 103 of file astobj2.c.
References AO2_MAGIC, ast_log(), and LOG_ERROR.
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 }