113 int *
i = (
int *) arg;
124 int *
i = (
int *) arg;
128 int *
i = (
int *) arg;
130 return (*
i - partial_key_match_range <= cmp_obj->
i
152 const struct test_obj *hash_obj = obj;
158static int test_sort_cb(
const void *obj_left,
const void *obj_right,
int flags)
160 const struct test_obj *test_left = obj_left;
163 const int *
i = obj_right;
165 return test_left->
i - *
i;
167 int *
i = (
int *) obj_right;
169 if (*
i - partial_key_match_range <= test_left->
i
174 return test_left->
i - *
i;
176 const struct test_obj *test_right = obj_right;
178 return test_left->
i - test_right->
i;
182#if defined(TEST_CONTAINER_DEBUG_DUMP)
192static void test_prnt_obj(
void *v_obj,
void *where,
ao2_prnt_fn *prnt)
246 "Orig container has an object %p not in the clone container.\n", obj);
283 for (num = 100; num--;) {
287 obj =
ao2_find(look_in, &tmp_obj, 0);
322 for (num = 75; num--;) {
360 for (num = 75; num--;) {
400 for (num = 100; num--;) {
435 tst_num, c_type, use_sort ?
"sorted" :
"non-sorted");
446 n_buckets = (
ast_random() % ((lim / 4) + 1)) + 1;
466 for (num = 0; num < lim; ++num) {
489 c_type, n_buckets, lim);
509 if (increment != lim) {
517 if (increment != lim) {
523 num = lim < 25 ? lim : 25;
621#if defined(TEST_CONTAINER_DEBUG_DUMP)
652 info->name =
"astobj2_test1";
653 info->category =
"/main/astobj2/";
654 info->summary =
"Test ao2 objects, containers, callbacks, and iterators";
656 "Builds ao2_containers with various item numbers, bucket sizes, cmp and hash "
657 "functions. Runs a series of tests to manipulate the container using callbacks "
658 "and iterators. Verifies expected behavior.";
695 static const int NUM_OBJS = 5;
701 info->name =
"astobj2_test2";
702 info->category =
"/main/astobj2/";
703 info->summary =
"Test a certain scenario using ao2 iterators";
705 "This test is aimed at testing for a specific regression that occurred. "
706 "Add some objects into a container. Mix finds and iteration and make "
707 "sure that the iterator still sees all objects.";
720 for (num = 1; num <= NUM_OBJS; num++) {
752 if (num != NUM_OBJS) {
762 tmp_obj.
i = NUM_OBJS;
779 if (num != NUM_OBJS) {
794 tmp_obj.
i = NUM_OBJS - 1;
808 if (num != NUM_OBJS) {
836 info->name =
"astobj2_test3";
837 info->category =
"/main/astobj2/";
838 info->summary =
"Test global ao2 holder";
840 "This test is to see if the global ao2 holder works as intended.";
854 obj->
i = ++num_objects;
872 obj->
i = ++num_objects;
898 obj->
i = ++num_objects;
929 "all destructors were not called, destructor count is %d\n",
934 "Destructor was called too many times, destructor count is %d\n",
941 ao2_t_ref(obj, -1,
"Test cleanup external object 1");
944 ao2_t_ref(obj2, -1,
"Test cleanup external object 2");
947 ao2_t_ref(obj3, -1,
"Test cleanup external object 3");
1043 for (idx = 0; idx < count; ++idx) {
1049 if (destroy_counter) {
1054 obj->
i = vector[idx];
1059 prefix, idx, vector[idx]);
1065 "%s: Unexpected container count. Expected:%d Got:%d\n",
1106 for (count = 0; count < 4; ++count) {
1115 if (destroy_counter) {
1171 const int *vector,
int count,
const char *
prefix,
struct ast_test *
test)
1186 for (idx = 0; idx < count; ++idx) {
1193 if (vector[idx] != obj->
i) {
1195 prefix, obj->
i, idx, vector[idx]);
1232 const int *vector,
int count,
const char *
prefix,
struct ast_test *
test)
1245 for (idx = 0; idx < count; ++idx) {
1252 if (vector[idx] != obj->
i) {
1254 prefix, obj->
i, idx, vector[idx]);
1289 const int *vector,
int count,
const char *
prefix,
struct ast_test *
test)
1302 for (idx = 0; idx < count; ++idx) {
1324 "%s: Too many objects found. Object %d, dup id %d\n",
1351 int destructor_count = 0;
1354 static const int test_initial[] = {
1355 1, 0, 2, 6, 4, 7, 5, 3, 9, 8
1359 static const int test_reverse[] = {
1360 8, 9, 3, 5, 7, 4, 6, 2, 0, 1
1362 static const int test_list_partial_forward[] = {
1365 static const int test_list_partial_backward[] = {
1370 static const int test_hash_end_forward[] = {
1371 0, 5, 1, 6, 2, 7, 3, 8, 4, 9
1373 static const int test_hash_end_backward[] = {
1374 9, 4, 8, 3, 7, 2, 6, 1, 5, 0
1376 static const int test_hash_begin_forward[] = {
1377 5, 0, 6, 1, 7, 2, 8, 3, 9, 4
1379 static const int test_hash_begin_backward[] = {
1380 4, 9, 3, 8, 2, 7, 1, 6, 0, 5
1382 static const int test_hash_partial_forward[] = {
1385 static const int test_hash_partial_backward[] = {
1421 "Iteration (ascending, insert end)",
test);
1424 "Iteration (descending, insert end)",
test);
1428 "Iteration (ascending, insert begin)",
test);
1431 "Iteration (descending, insert begin)",
test);
1435 test_hash_end_forward,
ARRAY_LEN(test_hash_end_forward),
1436 "Iteration (ascending, insert end)",
test);
1438 test_hash_end_backward,
ARRAY_LEN(test_hash_end_backward),
1439 "Iteration (descending, insert end)",
test);
1442 test_hash_begin_forward,
ARRAY_LEN(test_hash_begin_forward),
1443 "Iteration (ascending, insert begin)",
test);
1445 test_hash_begin_backward,
ARRAY_LEN(test_hash_begin_backward),
1446 "Iteration (descending, insert begin)",
test);
1457 "Traversal (ascending, insert end)",
test);
1460 "Traversal (descending, insert end)",
test);
1464 "Traversal (ascending, insert begin)",
test);
1467 "Traversal (descending, insert begin)",
test);
1471 test_hash_end_forward,
ARRAY_LEN(test_hash_end_forward),
1472 "Traversal (ascending, insert end)",
test);
1474 test_hash_end_backward,
ARRAY_LEN(test_hash_end_backward),
1475 "Traversal (descending, insert end)",
test);
1478 test_hash_begin_forward,
ARRAY_LEN(test_hash_begin_forward),
1479 "Traversal (ascending, insert begin)",
test);
1481 test_hash_begin_backward,
ARRAY_LEN(test_hash_begin_backward),
1482 "Traversal (descending, insert begin)",
test);
1495 test_list_partial_forward,
ARRAY_LEN(test_list_partial_forward),
1496 "Traversal OBJ_PARTIAL_KEY (ascending)",
test);
1499 test_list_partial_backward,
ARRAY_LEN(test_list_partial_backward),
1500 "Traversal OBJ_PARTIAL_KEY (descending)",
test);
1505 test_hash_partial_forward,
ARRAY_LEN(test_hash_partial_forward),
1506 "Traversal OBJ_PARTIAL_KEY (ascending)",
test);
1509 test_hash_partial_backward,
ARRAY_LEN(test_hash_partial_backward),
1510 "Traversal OBJ_PARTIAL_KEY (descending)",
test);
1525 if (destructor_count > 0) {
1527 "all destructors were not called, destructor count is %d\n",
1530 }
else if (destructor_count < 0) {
1532 "Destructor was called too many times, destructor count is %d\n",
1557 int destructor_count = 0;
1558 int duplicate_number = 100;
1561 static const int test_initial[] = {
1562 1, 0, 2, 6, 4, 7, 5, 3, 9, 8
1566 static const int test_forward[] = {
1567 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
1570 static const int test_backward[] = {
1571 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
1574 static const int test_partial_forward[] = {
1577 static const int test_partial_backward[] = {
1582 static const int test_hash_forward[] = {
1583 0, 5, 1, 6, 2, 7, 3, 8, 4, 9
1585 static const int test_hash_backward[] = {
1586 9, 4, 8, 3, 7, 2, 6, 1, 5, 0
1588 static const int test_hash_partial_forward[] = {
1591 static const int test_hash_partial_backward[] = {
1596 static const int test_dup_allow_forward[] = {
1599 static const int test_dup_allow_backward[] = {
1602 static const int test_dup_reject[] = {
1605 static const int test_dup_obj_reject_forward[] = {
1608 static const int test_dup_obj_reject_backward[] = {
1611 static const int test_dup_replace[] = {
1642#if defined(TEST_CONTAINER_DEBUG_DUMP)
1655 "Iteration (ascending)",
test);
1657 test_backward,
ARRAY_LEN(test_backward),
1658 "Iteration (descending)",
test);
1662 test_hash_forward,
ARRAY_LEN(test_hash_forward),
1663 "Iteration (ascending)",
test);
1665 test_hash_backward,
ARRAY_LEN(test_hash_backward),
1666 "Iteration (descending)",
test);
1676 "Traversal (ascending)",
test);
1678 test_backward,
ARRAY_LEN(test_backward),
1679 "Traversal (descending)",
test);
1683 test_hash_forward,
ARRAY_LEN(test_hash_forward),
1684 "Traversal (ascending, insert end)",
test);
1686 test_hash_backward,
ARRAY_LEN(test_hash_backward),
1687 "Traversal (descending)",
test);
1699 test_partial_forward,
ARRAY_LEN(test_partial_forward),
1700 "Traversal OBJ_PARTIAL_KEY (ascending)",
test);
1703 test_partial_backward,
ARRAY_LEN(test_partial_backward),
1704 "Traversal OBJ_PARTIAL_KEY (descending)",
test);
1709 test_hash_partial_forward,
ARRAY_LEN(test_hash_partial_forward),
1710 "Traversal OBJ_PARTIAL_KEY (ascending)",
test);
1713 test_hash_partial_backward,
ARRAY_LEN(test_hash_partial_backward),
1714 "Traversal OBJ_PARTIAL_KEY (descending)",
test);
1728#if defined(TEST_CONTAINER_DEBUG_DUMP)
1737 test_dup_allow_forward,
ARRAY_LEN(test_dup_allow_forward),
1738 "Duplicates (ascending, DUPS_ALLOW)",
test);
1740 test_dup_allow_backward,
ARRAY_LEN(test_dup_allow_backward),
1741 "Duplicates (descending, DUPS_ALLOW)",
test);
1780 test_dup_reject,
ARRAY_LEN(test_dup_reject),
1781 "Duplicates (ascending, DUPS_REJECT)",
test);
1783 test_dup_reject,
ARRAY_LEN(test_dup_reject),
1784 "Duplicates (descending, DUPS_REJECT)",
test);
1823 test_dup_obj_reject_forward,
ARRAY_LEN(test_dup_obj_reject_forward),
1824 "Duplicates (ascending, DUPS_OBJ_REJECT)",
test);
1826 test_dup_obj_reject_backward,
ARRAY_LEN(test_dup_obj_reject_backward),
1827 "Duplicates (descending, DUPS_OBJ_REJECT)",
test);
1866 test_dup_replace,
ARRAY_LEN(test_dup_replace),
1867 "Duplicates (ascending, DUPS_REPLACE)",
test);
1869 test_dup_replace,
ARRAY_LEN(test_dup_replace),
1870 "Duplicates (descending, DUPS_REPLACE)",
test);
1881 if (destructor_count > 0) {
1883 "all destructors were not called, destructor count is %d\n",
1886 }
else if (destructor_count < 0) {
1888 "Destructor was called too many times, destructor count is %d\n",
1902 info->name =
"astobj2_test4";
1903 info->category =
"/main/astobj2/";
1904 info->summary =
"Test container traversal/iteration";
1906 "This test is to see if the container traversal/iteration works "
1907 "as intended for each supported container type.";
1995 int reportcount = iterations / 5;
1996 struct timeval start;
1999 for (i = 1 ; i <= iterations && res ==
AST_TEST_PASS ; i++) {
2000 if (i % reportcount == 0 && i != iterations) {
2020#define ITERATIONS 25000
2022#define ITERATIONS 100000
2029 info->name =
"astobj2_test_perf";
2030 info->category =
"/main/astobj2/perf/";
2031 info->summary =
"Test container performance";
2033 "Runs container traversal tests.";
Asterisk main include file. File version handling, generic pbx functions.
#define ao2_t_ref(o, delta, tag)
#define ao2_iterator_next(iter)
#define ao2_link(container, obj)
Add an object to a container.
@ AO2_ALLOC_OPT_LOCK_MUTEX
#define ao2_t_iterator_next(iter, tag)
int ao2_match_by_addr(void *obj, void *arg, int flags)
A common ao2_callback is one that matches by address.
int ao2_container_check(struct ao2_container *self, enum search_flags flags)
Perform an integrity check on the specified container.
#define ao2_t_global_obj_replace_unref(holder, obj, tag)
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_t_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn, tag)
#define ao2_t_link(container, obj, tag)
void ao2_container_stats(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt)
Display statistics of the specified container.
int() ao2_callback_fn(void *obj, void *arg, int flags)
Type of a generic callback function.
@ AO2_ITERATOR_DESCENDING
#define ao2_find(container, arg, flags)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag)
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag)
#define ao2_t_unlink(container, obj, tag)
#define ao2_t_global_obj_replace(holder, obj, tag)
void ao2_container_dump(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj)
Display contents of the specified container.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
search_flags
Flags passed to ao2_callback_fn(), ao2_hash_fn(), and ao2_sort_fn() to modify behaviour.
@ OBJ_ORDER_DESCENDING
Traverse in descending order (Last to first container object)
@ OBJ_ORDER_ASCENDING
Traverse in ascending order (First to last container object)
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
#define ao2_alloc(data_size, destructor_fn)
#define ao2_t_global_obj_release(holder, tag)
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
#define ao2_t_global_obj_ref(holder, tag)
void() ao2_prnt_fn(void *where, const char *fmt,...)
Print output.
#define ao2_container_clone(orig, flags)
Create a clone/copy of the given container.
@ AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT
Reject duplicate objects in container.
@ AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN
Insert objects at the beginning of the container. (Otherwise it is the opposite; insert at the end....
@ AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW
Allow objects with duplicate keys in container.
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE
Replace objects with duplicate keys in container.
static char prefix[MAX_PREFIX]
Asterisk module definitions.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
static void * cleanup(void *unused)
struct ao2_container * container
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
#define ast_test_debug(test, fmt,...)
#define AST_TEST_REGISTER(cb)
#define ast_test_status_update(a, b, c...)
#define AST_TEST_UNREGISTER(cb)
static enum ast_test_result_state test_performance(struct ast_test *test, enum test_container_type type, unsigned int copt)
static int insert_test_duplicates(struct ao2_container *container, int *destroy_counter, int number, const char *prefix, struct ast_test *test)
static int test_ao2_iteration(int res, struct ao2_container *container, enum ao2_iterator_flags flags, const int *vector, int count, const char *prefix, struct ast_test *test)
static void test_obj_destructor(void *v_obj)
static int test_traversal_sorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)
static int multiple_cb(void *obj, void *arg, int flag)
static int test_ao2_find_w_OBJ_POINTER(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
static int test_ao2_find_w_OBJ_PARTIAL_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
int partial_key_match_range
static int test_expected_duplicates(int res, struct ao2_container *container, enum search_flags flags, int number, const int *vector, int count, const char *prefix, struct ast_test *test)
static int test_container_clone(int res, struct ao2_container *orig, struct ast_test *test)
static int test_ao2_find_w_no_flags(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
static int test_hash_cb(const void *obj, const int flags)
static int test_ao2_find_w_OBJ_KEY(int res, struct ao2_container *look_in, int limit, struct ast_test *test)
static int test_cmp_cb(void *obj, void *arg, int flags)
static struct ao2_container * test_make_sorted(enum test_container_type type, int options)
static int all_but_one_cb(void *obj, void *arg, int flag)
static int test_traversal_nonsorted(int res, int tst_num, enum test_container_type type, struct ast_test *test)
static int test_ao2_callback_traversal(int res, struct ao2_container *container, enum search_flags flags, ao2_callback_fn *cmp_fn, void *arg, const int *vector, int count, const char *prefix, struct ast_test *test)
static int increment_cb(void *obj, void *arg, int flag)
static AO2_GLOBAL_OBJ_STATIC(astobj2_holder)
static enum ast_test_result_state testloop(struct ast_test *test, enum test_container_type type, int copt, int iterations)
static int test_sort_cb(const void *obj_left, const void *obj_right, int flags)
static int load_module(void)
AST_TEST_DEFINE(astobj2_test_1)
static int unload_module(void)
static const char * test_container2str(enum test_container_type type)
static int astobj2_test_1_helper(int tst_num, enum test_container_type type, int use_sort, unsigned int lim, struct ast_test *test)
static int insert_test_vector(struct ao2_container *container, int *destroy_counter, const int *vector, int count, const char *prefix, struct ast_test *test)
static struct ao2_container * test_make_nonsorted(enum test_container_type type, int options)
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
long int ast_random(void)