#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 | __ao2_container |
struct | __priv_data |
struct | ao2_stats |
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 (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 (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 (ao2_container *c) |
void * | ao2_find (ao2_container *c, void *arg, enum search_flags flags) |
ao2_iterator | ao2_iterator_init (ao2_container *c, int flags) |
void * | ao2_iterator_next (ao2_iterator *a) |
int | ao2_lock (void *user_data) |
int | ao2_ref (void *user_data, const int delta) |
void * | ao2_unlink (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 | handle_astobj2_stats (int fd, int argc, char *argv[]) |
static int | handle_astobj2_test (int fd, int argc, char *argv[]) |
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 | |
static int | match_by_addr (void *user_data, void *arg, int flags) |
another convenience function is a callback that matches on address | |
static int | print_cb (void *obj, void *arg, int flag) |
Variables | |
static struct ao2_stats | ao2 |
static struct ast_cli_entry | cli_astobj2 [] |
#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 120 of file astobj2.c.
Referenced by ao2_alloc(), and ao2_callback().
void* __ao2_link | ( | ao2_container * | c, | |
void * | user_data, | |||
int | iax2_hack | |||
) |
Definition at line 319 of file astobj2.c.
References ao2_lock(), ao2_unlock(), ast_calloc, AST_LIST_INSERT_HEAD, AST_LIST_INSERT_TAIL, and INTERNAL_OBJ().
Referenced by set_config().
00320 { 00321 int i; 00322 /* create a new list entry */ 00323 struct bucket_list *p; 00324 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00325 00326 if (!obj) 00327 return NULL; 00328 00329 if (INTERNAL_OBJ(c) == NULL) 00330 return NULL; 00331 00332 p = ast_calloc(1, sizeof(*p)); 00333 if (!p) 00334 return NULL; 00335 00336 i = c->hash_fn(user_data, OBJ_POINTER); 00337 00338 ao2_lock(c); 00339 i %= c->n_buckets; 00340 p->astobj = obj; 00341 p->version = ast_atomic_fetchadd_int(&c->version, 1); 00342 if (iax2_hack) 00343 AST_LIST_INSERT_HEAD(&c->buckets[i], p, entry); 00344 else 00345 AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry); 00346 ast_atomic_fetchadd_int(&c->elements, 1); 00347 ao2_unlock(c); 00348 00349 return p; 00350 }
void* ao2_alloc | ( | size_t | data_size, | |
ao2_destructor_fn | destructor_fn | |||
) |
Definition at line 192 of file astobj2.c.
References ao2, AO2_MAGIC, ast_calloc, ast_mutex_init(), EXTERNAL_OBJ, ao2_stats::total_mem, ao2_stats::total_objects, and ao2_stats::total_refs.
Referenced by ao2_container_alloc(), build_peer(), build_user(), and handle_astobj2_test().
00193 { 00194 /* allocation */ 00195 struct astobj2 *obj; 00196 00197 if (data_size < sizeof(void *)) 00198 data_size = sizeof(void *); 00199 00200 obj = ast_calloc(1, sizeof(*obj) + data_size); 00201 00202 if (obj == NULL) 00203 return NULL; 00204 00205 ast_mutex_init(&obj->priv_data.lock); 00206 obj->priv_data.magic = AO2_MAGIC; 00207 obj->priv_data.data_size = data_size; 00208 obj->priv_data.ref_counter = 1; 00209 obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */ 00210 ast_atomic_fetchadd_int(&ao2.total_objects, 1); 00211 ast_atomic_fetchadd_int(&ao2.total_mem, data_size); 00212 ast_atomic_fetchadd_int(&ao2.total_refs, 1); 00213 00214 /* return a pointer to the user data */ 00215 return EXTERNAL_OBJ(obj); 00216 }
void* ao2_callback | ( | 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 387 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(), cb_true(), EXTERNAL_OBJ, free, INTERNAL_OBJ(), last, LOG_WARNING, match(), and match_by_addr().
Referenced by ao2_find(), ao2_unlink(), container_destruct(), delete_users(), handle_astobj2_test(), load_module(), and reload_config().
00390 { 00391 int i, last; /* search boundaries */ 00392 void *ret = NULL; 00393 00394 if (INTERNAL_OBJ(c) == NULL) /* safety check on the argument */ 00395 return NULL; 00396 00397 if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) { 00398 ast_log(LOG_WARNING, "multiple data return not implemented yet (flags %x)\n", flags); 00399 return NULL; 00400 } 00401 00402 /* override the match function if necessary */ 00403 #if 0 00404 /* Removing this slightly changes the meaning of OBJ_POINTER, but makes it 00405 * do what I want it to. I'd like to hint to ao2_callback that the arg is 00406 * of the same object type, so it can be passed to the hash function. 00407 * However, I don't want to imply that this is the object being searched for. */ 00408 if (flags & OBJ_POINTER) 00409 cb_fn = match_by_addr; 00410 else 00411 #endif 00412 if (cb_fn == NULL) /* if NULL, match everything */ 00413 cb_fn = cb_true; 00414 /* 00415 * XXX this can be optimized. 00416 * If we have a hash function and lookup by pointer, 00417 * run the hash function. Otherwise, scan the whole container 00418 * (this only for the time being. We need to optimize this.) 00419 */ 00420 if ((flags & OBJ_POINTER)) /* we know hash can handle this case */ 00421 i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets; 00422 else /* don't know, let's scan all buckets */ 00423 i = -1; /* XXX this must be fixed later. */ 00424 00425 /* determine the search boundaries: i..last-1 */ 00426 if (i < 0) { 00427 i = 0; 00428 last = c->n_buckets; 00429 } else { 00430 last = i + 1; 00431 } 00432 00433 ao2_lock(c); /* avoid modifications to the content */ 00434 00435 for (; i < last ; i++) { 00436 /* scan the list with prev-cur pointers */ 00437 struct bucket_list *cur; 00438 00439 AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) { 00440 int match = cb_fn(EXTERNAL_OBJ(cur->astobj), arg, flags) & (CMP_MATCH | CMP_STOP); 00441 00442 /* we found the object, performing operations according flags */ 00443 if (match == 0) { /* no match, no stop, continue */ 00444 continue; 00445 } else if (match == CMP_STOP) { /* no match but stop, we are done */ 00446 i = last; 00447 break; 00448 } 00449 /* we have a match (CMP_MATCH) here */ 00450 if (!(flags & OBJ_NODATA)) { /* if must return the object, record the value */ 00451 /* it is important to handle this case before the unlink */ 00452 ret = EXTERNAL_OBJ(cur->astobj); 00453 ao2_ref(ret, 1); 00454 } 00455 00456 if (flags & OBJ_UNLINK) { /* must unlink */ 00457 struct bucket_list *x = cur; 00458 00459 /* we are going to modify the container, so update version */ 00460 ast_atomic_fetchadd_int(&c->version, 1); 00461 AST_LIST_REMOVE_CURRENT(&c->buckets[i], entry); 00462 /* update number of elements and version */ 00463 ast_atomic_fetchadd_int(&c->elements, -1); 00464 ao2_ref(EXTERNAL_OBJ(x->astobj), -1); 00465 free(x); /* free the link record */ 00466 } 00467 00468 if ((match & CMP_STOP) || (flags & OBJ_MULTIPLE) == 0) { 00469 /* We found the only match we need */ 00470 i = last; /* force exit from outer loop */ 00471 break; 00472 } 00473 if (!(flags & OBJ_NODATA)) { 00474 #if 0 /* XXX to be completed */ 00475 /* 00476 * This is the multiple-return case. We need to link 00477 * the object in a list. The refcount is already increased. 00478 */ 00479 #endif 00480 } 00481 } 00482 AST_LIST_TRAVERSE_SAFE_END 00483 } 00484 ao2_unlock(c); 00485 return ret; 00486 }
ao2_container* ao2_container_alloc | ( | const uint | n_buckets, | |
ao2_hash_fn | hash_fn, | |||
ao2_callback_fn | cmp_fn | |||
) |
Definition at line 276 of file astobj2.c.
References ao2, ao2_alloc(), container_destruct(), hash_zero(), and ao2_stats::total_containers.
Referenced by handle_astobj2_test(), and load_module().
00278 { 00279 /* XXX maybe consistency check on arguments ? */ 00280 /* compute the container size */ 00281 size_t container_size = sizeof(ao2_container) + n_buckets * sizeof(struct bucket); 00282 00283 ao2_container *c = ao2_alloc(container_size, container_destruct); 00284 00285 if (!c) 00286 return NULL; 00287 00288 c->version = 1; /* 0 is a reserved value here */ 00289 c->n_buckets = n_buckets; 00290 c->hash_fn = hash_fn ? hash_fn : hash_zero; 00291 c->cmp_fn = cmp_fn; 00292 ast_atomic_fetchadd_int(&ao2.total_containers, 1); 00293 00294 return c; 00295 }
int ao2_container_count | ( | ao2_container * | c | ) |
void* ao2_find | ( | ao2_container * | c, | |
void * | arg, | |||
enum search_flags | flags | |||
) |
the find function just invokes the default callback with some reasonable flags.
Definition at line 491 of file astobj2.c.
References ao2_callback().
Referenced by __expire_registry(), authenticate_request(), authenticate_verify(), build_peer(), build_user(), find_peer(), and iax2_destroy_helper().
00492 { 00493 return ao2_callback(c, flags, c->cmp_fn, arg); 00494 }
ao2_iterator ao2_iterator_init | ( | ao2_container * | c, | |
int | flags | |||
) |
initialize an iterator so we start from the first object
Definition at line 499 of file astobj2.c.
References __ao2_iterator::c.
Referenced by __iax2_show_peers(), authenticate_reply(), check_access(), complete_iax2_show_peer(), handle_astobj2_test(), iax2_getpeername(), iax2_getpeertrunk(), iax2_show_users(), prune_peers(), and prune_users().
00500 { 00501 ao2_iterator a = { 00502 .c = c, 00503 .flags = flags 00504 }; 00505 00506 return a; 00507 }
void* ao2_iterator_next | ( | ao2_iterator * | a | ) |
Definition at line 512 of file astobj2.c.
References ao2_lock(), AST_LIST_NEXT, AST_LIST_TRAVERSE, __ao2_iterator::bucket, __ao2_iterator::c, __ao2_iterator::c_version, F_AO2I_DONTLOCK, __ao2_iterator::flags, INTERNAL_OBJ(), __ao2_iterator::obj, and __ao2_iterator::version.
Referenced by __iax2_show_peers(), authenticate_reply(), check_access(), complete_iax2_show_peer(), handle_astobj2_test(), iax2_getpeername(), iax2_getpeertrunk(), iax2_show_users(), prune_peers(), and prune_users().
00513 { 00514 int lim; 00515 struct bucket_list *p = NULL; 00516 00517 if (INTERNAL_OBJ(a->c) == NULL) 00518 return NULL; 00519 00520 if (!(a->flags & F_AO2I_DONTLOCK)) 00521 ao2_lock(a->c); 00522 00523 /* optimization. If the container is unchanged and 00524 * we have a pointer, try follow it 00525 */ 00526 if (a->c->version == a->c_version && (p = a->obj) ) { 00527 if ( (p = AST_LIST_NEXT(p, entry)) ) 00528 goto found; 00529 /* nope, start from the next bucket */ 00530 a->bucket++; 00531 a->version = 0; 00532 a->obj = NULL; 00533 } 00534 00535 lim = a->c->n_buckets; 00536 00537 /* Browse the buckets array, moving to the next 00538 * buckets if we don't find the entry in the current one. 00539 * Stop when we find an element with version number greater 00540 * than the current one (we reset the version to 0 when we 00541 * switch buckets). 00542 */ 00543 for (; a->bucket < lim; a->bucket++, a->version = 0) { 00544 /* scan the current bucket */ 00545 AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) { 00546 if (p->version > a->version) 00547 goto found; 00548 } 00549 } 00550 00551 found: 00552 if (p) { 00553 a->version = p->version; 00554 a->obj = p; 00555 a->c_version = a->c->version; 00556 /* inc refcount of returned object */ 00557 ao2_ref(EXTERNAL_OBJ(p->astobj), 1); 00558 } 00559 00560 if (!(a->flags & F_AO2I_DONTLOCK)) 00561 ao2_unlock(a->c); 00562 00563 return p ? EXTERNAL_OBJ(p->astobj) : NULL; 00564 }
int ao2_lock | ( | void * | user_data | ) |
Definition at line 122 of file astobj2.c.
References ao2, ast_mutex_lock(), INTERNAL_OBJ(), __priv_data::lock, astobj2::priv_data, and ao2_stats::total_locked.
Referenced by __ao2_link(), ao2_callback(), and ao2_iterator_next().
00123 { 00124 struct astobj2 *p = INTERNAL_OBJ(user_data); 00125 00126 if (p == NULL) 00127 return -1; 00128 00129 ast_atomic_fetchadd_int(&ao2.total_locked, 1); 00130 00131 return ast_mutex_lock(&p->priv_data.lock); 00132 }
int ao2_ref | ( | void * | user_data, | |
const int | delta | |||
) |
Definition at line 149 of file astobj2.c.
References ao2, ast_log(), ast_mutex_destroy(), __priv_data::data_size, __priv_data::destructor_fn, free, INTERNAL_OBJ(), __priv_data::lock, LOG_ERROR, astobj2::priv_data, __priv_data::ref_counter, ao2_stats::total_mem, ao2_stats::total_objects, and ao2_stats::total_refs.
Referenced by __unload_module(), ao2_callback(), cd_cb(), handle_astobj2_test(), load_module(), peer_ref(), peer_unref(), user_ref(), and user_unref().
00150 { 00151 int current_value; 00152 int ret; 00153 struct astobj2 *obj = INTERNAL_OBJ(user_data); 00154 00155 if (obj == NULL) 00156 return -1; 00157 00158 /* if delta is 0, just return the refcount */ 00159 if (delta == 0) 00160 return (obj->priv_data.ref_counter); 00161 00162 /* we modify with an atomic operation the reference counter */ 00163 ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta); 00164 ast_atomic_fetchadd_int(&ao2.total_refs, delta); 00165 current_value = ret + delta; 00166 00167 /* this case must never happen */ 00168 if (current_value < 0) 00169 ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data); 00170 00171 if (current_value <= 0) { /* last reference, destroy the object */ 00172 if (obj->priv_data.destructor_fn != NULL) 00173 obj->priv_data.destructor_fn(user_data); 00174 00175 ast_mutex_destroy(&obj->priv_data.lock); 00176 ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size); 00177 /* for safety, zero-out the astobj2 header and also the 00178 * first word of the user-data, which we make sure is always 00179 * allocated. */ 00180 bzero(obj, sizeof(struct astobj2 *) + sizeof(void *) ); 00181 free(obj); 00182 ast_atomic_fetchadd_int(&ao2.total_objects, -1); 00183 } 00184 00185 return ret; 00186 }
void* ao2_unlink | ( | ao2_container * | c, | |
void * | user_data | |||
) |
Definition at line 364 of file astobj2.c.
References ao2_callback(), INTERNAL_OBJ(), and match_by_addr().
Referenced by __expire_registry(), build_peer(), build_user(), handle_astobj2_test(), prune_peers(), and prune_users().
00365 { 00366 if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */ 00367 return NULL; 00368 00369 ao2_callback(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, match_by_addr, user_data); 00370 00371 return NULL; 00372 }
int ao2_unlock | ( | void * | user_data | ) |
Definition at line 134 of file astobj2.c.
References ao2, ast_mutex_unlock(), INTERNAL_OBJ(), __priv_data::lock, astobj2::priv_data, and ao2_stats::total_locked.
Referenced by __ao2_link(), and ao2_callback().
00135 { 00136 struct astobj2 *p = INTERNAL_OBJ(user_data); 00137 00138 if (p == NULL) 00139 return -1; 00140 00141 ast_atomic_fetchadd_int(&ao2.total_locked, -1); 00142 00143 return ast_mutex_unlock(&p->priv_data.lock); 00144 }
AST_LIST_HEAD_NOLOCK | ( | bucket | , | |
bucket_list | ||||
) |
int astobj2_init | ( | void | ) |
Definition at line 684 of file astobj2.c.
References ARRAY_LEN, ast_cli_register_multiple(), and cli_astobj2.
00685 { 00686 ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2)); 00687 return 0; 00688 }
static int cb_true | ( | void * | user_data, | |
void * | arg, | |||
int | flags | |||
) | [static] |
special callback that matches all
Definition at line 377 of file astobj2.c.
Referenced by ao2_callback().
static int cd_cb | ( | void * | obj, | |
void * | arg, | |||
int | flag | |||
) | [static] |
Definition at line 569 of file astobj2.c.
References ao2_ref().
Referenced by container_destruct().
00570 { 00571 ao2_ref(obj, -1); 00572 return 0; 00573 }
static void container_destruct | ( | void * | c | ) | [static] |
Definition at line 575 of file astobj2.c.
References ao2, ao2_callback(), cd_cb(), and ao2_stats::total_containers.
Referenced by ao2_container_alloc().
00576 { 00577 ao2_container *c = _c; 00578 00579 ao2_callback(c, OBJ_UNLINK, cd_cb, NULL); 00580 ast_atomic_fetchadd_int(&ao2.total_containers, -1); 00581 }
static int handle_astobj2_stats | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 595 of file astobj2.c.
References ao2, ast_cli(), ao2_stats::total_containers, ao2_stats::total_locked, ao2_stats::total_mem, ao2_stats::total_objects, and ao2_stats::total_refs.
Referenced by handle_astobj2_test().
00596 { 00597 ast_cli(fd, "Objects : %d\n", ao2.total_objects); 00598 ast_cli(fd, "Containers : %d\n", ao2.total_containers); 00599 ast_cli(fd, "Memory : %d\n", ao2.total_mem); 00600 ast_cli(fd, "Locked : %d\n", ao2.total_locked); 00601 ast_cli(fd, "Refs : %d\n", ao2.total_refs); 00602 return 0; 00603 }
static int handle_astobj2_test | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 608 of file astobj2.c.
References ao2_alloc(), ao2_callback(), ao2_container_alloc(), ao2_iterator_init(), ao2_iterator_next(), ao2_ref(), ao2_unlink(), ast_add_profile(), ast_cli(), ast_mark(), ast_verbose(), handle_astobj2_stats(), and print_cb().
00609 { 00610 ao2_container *c1; 00611 int i, lim; 00612 char *obj; 00613 static int prof_id = -1; 00614 00615 if (prof_id == -1) 00616 prof_id = ast_add_profile("ao2_alloc", 0); 00617 00618 ast_cli(fd, "argc %d argv %s %s %s\n", argc, argv[0], argv[1], argv[2]); 00619 lim = atoi(argv[2]); 00620 ast_cli(fd, "called astobj_test\n"); 00621 00622 handle_astobj2_stats(fd, 0, NULL); 00623 /* 00624 * allocate a container with no default callback, and no hash function. 00625 * No hash means everything goes in the same bucket. 00626 */ 00627 c1 = ao2_container_alloc(100, NULL /* no callback */, NULL /* no hash */); 00628 ast_cli(fd, "container allocated as %p\n", c1); 00629 00630 /* 00631 * fill the container with objects. 00632 * ao2_alloc() gives us a reference which we pass to the 00633 * container when we do the insert. 00634 */ 00635 for (i = 0; i < lim; i++) { 00636 ast_mark(prof_id, 1 /* start */); 00637 obj = ao2_alloc(80, NULL); 00638 ast_mark(prof_id, 0 /* stop */); 00639 ast_cli(fd, "object %d allocated as %p\n", i, obj); 00640 sprintf(obj, "-- this is obj %d --", i); 00641 ao2_link(c1, obj); 00642 } 00643 ast_cli(fd, "testing callbacks\n"); 00644 ao2_callback(c1, 0, print_cb, &fd); 00645 00646 ast_cli(fd, "testing iterators, remove every second object\n"); 00647 { 00648 ao2_iterator ai; 00649 int x = 0; 00650 00651 ai = ao2_iterator_init(c1, 0); 00652 while ( (obj = ao2_iterator_next(&ai)) ) { 00653 ast_cli(fd, "iterator on <%s>\n", obj); 00654 if (x++ & 1) 00655 ao2_unlink(c1, obj); 00656 ao2_ref(obj, -1); 00657 } 00658 ast_cli(fd, "testing iterators again\n"); 00659 ai = ao2_iterator_init(c1, 0); 00660 while ( (obj = ao2_iterator_next(&ai)) ) { 00661 ast_cli(fd, "iterator on <%s>\n", obj); 00662 ao2_ref(obj, -1); 00663 } 00664 } 00665 ast_cli(fd, "testing callbacks again\n"); 00666 ao2_callback(c1, 0, print_cb, &fd); 00667 00668 ast_verbose("now you should see an error message:\n"); 00669 ao2_ref(&i, -1); /* i is not a valid object so we print an error here */ 00670 00671 ast_cli(fd, "destroy container\n"); 00672 ao2_ref(c1, -1); /* destroy container */ 00673 handle_astobj2_stats(fd, 0, NULL); 00674 return 0; 00675 }
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 267 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 97 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().
00098 { 00099 struct astobj2 *p; 00100 00101 if (!user_data) { 00102 ast_log(LOG_ERROR, "user_data is NULL\n"); 00103 return NULL; 00104 } 00105 00106 p = (struct astobj2 *) ((char *) user_data - sizeof(*p)); 00107 if (AO2_MAGIC != (p->priv_data.magic) ) { 00108 ast_log(LOG_ERROR, "bad magic number 0x%x for %p\n", p->priv_data.magic, p); 00109 p = NULL; 00110 } 00111 00112 return p; 00113 }
static int match_by_addr | ( | void * | user_data, | |
void * | arg, | |||
int | flags | |||
) | [static] |
another convenience function is a callback that matches on address
Definition at line 355 of file astobj2.c.
Referenced by ao2_callback(), and ao2_unlink().
00356 { 00357 return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0; 00358 }
static int print_cb | ( | void * | obj, | |
void * | arg, | |||
int | flag | |||
) | [static] |
Definition at line 68 of file astobj2.c.
Referenced by ao2_alloc(), ao2_container_alloc(), ao2_lock(), ao2_ref(), ao2_unlock(), container_destruct(), and handle_astobj2_stats().
struct ast_cli_entry cli_astobj2[] [static] |
Initial value:
{ { { "astobj2", "stats", NULL }, handle_astobj2_stats, "Print astobj2 statistics", }, { { "astobj2", "test", NULL } , handle_astobj2_test, "Test astobj2", }, }
Definition at line 677 of file astobj2.c.
Referenced by astobj2_init().