コード例 #1
0
ファイル: hashtest2.c プロジェクト: mtulio/mtulio
static void run_hashtest(int numthr)
{
	pthread_t thr[numthr];
	void *thrres[numthr];
	int i;
	
	/* init a single global hashtab, then... */
	glob_hashtab = ao2_container_alloc(180000, hash_string, hashtab_compare_strings);

	/* set a random seed  */
	glob_seed = (unsigned int)time(0);
	srand(glob_seed);
	
	/* create threads, each running hashtest */
	for(i=0;i<numthr;i++)
	{
		unsigned long z = rand();
		
		printf("starting hashtest thread %d....\n",i+1);
		if (ast_pthread_create(&thr[i], NULL, hashtest, (void*)z)) {
			printf("Sorry, couldn't create thread #%d\n", i+1);
		}
		printf("hashtest thread spawned.... \n");
	}
	/* collect threads, each running hashtest */
	for(i=0;i<numthr;i++)
	{
		printf("waiting for thread %d....\n", i+1);
		if (pthread_join(thr[i], &thrres[i])) {
			printf("Sorry, couldn't join thread #%d\n", i+1);
		}
		printf("hashtest thread %d done.... \n",i+1);
	}
	/* user has to kill/intr the process to stop the test? */
}
コード例 #2
0
ファイル: res_pjsip_mwi.c プロジェクト: juned/asterisk
static int load_module(void)
{
	CHECK_PJSIP_MODULE_LOADED();

	if (ast_sip_register_subscription_handler(&mwi_handler)) {
		return AST_MODULE_LOAD_DECLINE;
	}

	unsolicited_mwi = ao2_container_alloc(MWI_BUCKETS, mwi_sub_hash, mwi_sub_cmp);
	if (!unsolicited_mwi) {
		ast_sip_unregister_subscription_handler(&mwi_handler);
		return AST_MODULE_LOAD_DECLINE;
	}

	create_mwi_subscriptions();
	ast_sorcery_observer_add(ast_sip_get_sorcery(), "contact", &mwi_contact_observer);

	if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED)) {
		ast_sip_push_task(NULL, send_initial_notify_all, NULL);
	} else {
		stasis_subscribe_pool(ast_manager_get_topic(), mwi_startup_event_cb, NULL);
	}

	return AST_MODULE_LOAD_SUCCESS;
}
コード例 #3
0
ファイル: res_pjsip_mwi.c プロジェクト: lyx2014/Asterisk
static void create_mwi_subscriptions(void)
{
	struct ao2_container *mwi_subscriptions = ao2_container_alloc(MWI_BUCKETS, mwi_sub_hash, mwi_sub_cmp);
	RAII_VAR(struct ao2_container *, old_mwi_subscriptions, ao2_global_obj_ref(unsolicited_mwi), ao2_cleanup);
	RAII_VAR(struct ao2_container *, endpoints, ast_sorcery_retrieve_by_fields(
				ast_sip_get_sorcery(), "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL),
			ao2_cleanup);

	if (!mwi_subscriptions) {
		return;
	}

	/* We remove all the old stasis subscriptions first before applying the new configuration. This
	 * prevents a situation where there might be multiple overlapping stasis subscriptions for an
	 * endpoint for mailboxes. Though there may be mailbox changes during the gap between unsubscribing
	 * and resubscribing, up-to-date mailbox state will be sent out to the endpoint when the
	 * new stasis subscription is established
	 */
	if (old_mwi_subscriptions) {
		ao2_callback(old_mwi_subscriptions, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe, NULL);
	}
	ao2_callback(endpoints, OBJ_NODATA, create_mwi_subscriptions_for_endpoint, mwi_subscriptions);
	ao2_global_obj_replace_unref(unsolicited_mwi, mwi_subscriptions);
	ao2_ref(mwi_subscriptions, -1);
}
コード例 #4
0
static int load_module(void)
{
	if (!(multiplexed_threads = ao2_container_alloc(MULTIPLEXED_BUCKETS, NULL, NULL))) {
		return AST_MODULE_LOAD_DECLINE;
	}

	return ast_bridge_technology_register(&multiplexed_bridge);
}
コード例 #5
0
static int ami_show_registrations(struct mansession *s, const struct message *m)
{
	int count = 0;
	struct ast_sip_ami ami = { .s = s, .m = m, .arg = &count, .action_id = astman_get_header(m, "ActionID"), };

	astman_send_listack(s, m, "Following are Events for each Inbound "
			    "registration", "start");

	ami_registrations_endpoints(&ami);

	astman_send_list_complete_start(s, m, "InboundRegistrationDetailComplete", count);
	astman_send_list_complete_end(s);
	return 0;
}

#define AMI_SHOW_REGISTRATIONS "PJSIPShowRegistrationsInbound"

static pjsip_module registrar_module = {
	.name = { "Registrar", 9 },
	.id = -1,
	.priority = PJSIP_MOD_PRIORITY_APPLICATION,
	.on_rx_request = registrar_on_rx_request,
};

static int load_module(void)
{
	const pj_str_t STR_REGISTER = { "REGISTER", 8 };

	CHECK_PJSIP_MODULE_LOADED();

	if (!(serializers = ao2_container_alloc(
		      SERIALIZER_BUCKETS, serializer_hash, serializer_cmp))) {
		return AST_MODULE_LOAD_DECLINE;
	}

	if (ast_sip_register_service(&registrar_module)) {
		return AST_MODULE_LOAD_DECLINE;
	}

	if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
		ast_sip_unregister_service(&registrar_module);
		return AST_MODULE_LOAD_DECLINE;
	}

	ast_manager_register_xml(AMI_SHOW_REGISTRATIONS, EVENT_FLAG_SYSTEM,
				 ami_show_registrations);

	return AST_MODULE_LOAD_SUCCESS;
}

static int unload_module(void)
{
	ast_manager_unregister(AMI_SHOW_REGISTRATIONS);
	ast_sip_unregister_service(&registrar_module);

	ao2_cleanup(serializers);
	return 0;
}
コード例 #6
0
/*! \brief Function called to load the module */
static int load_module(void)
{
	if (!(cli_aliases = ao2_container_alloc(MAX_ALIAS_BUCKETS, alias_hash_cb, alias_cmp_cb))) {
		return AST_MODULE_LOAD_DECLINE;
	}

	load_config(0);

	ast_cli_register_multiple(cli_alias, ARRAY_LEN(cli_alias));

	return AST_MODULE_LOAD_SUCCESS;
}
コード例 #7
0
ファイル: cel.c プロジェクト: hardikk/digium-asterisk
int ast_cel_engine_init(void)
{
	if (!(appset = ao2_container_alloc(NUM_APP_BUCKETS, app_hash, app_cmp))) {
		return -1;
	}
	if (!(linkedids = ao2_container_alloc(NUM_APP_BUCKETS, lid_hash, lid_cmp))) {
		ao2_ref(appset, -1);
		return -1;
	}

	if (do_reload() || ast_cli_register(&cli_status)) {
		ao2_ref(appset, -1);
		appset = NULL;
		ao2_ref(linkedids, -1);
		linkedids = NULL;
		return -1;
	}

	ast_register_atexit(ast_cel_engine_term);

	return 0;
}
コード例 #8
0
static int load_module(void)
{
	if (!(multiplexed_threads = ao2_container_alloc(MULTIPLEXED_BUCKETS, NULL, NULL))) {
		return AST_MODULE_LOAD_DECLINE;
	}
	if (!(multiplexed_bridge.format_capabilities = ast_format_cap_alloc())) {
		return AST_MODULE_LOAD_DECLINE;
	}
	ast_format_cap_add_all_by_type(multiplexed_bridge.format_capabilities, AST_FORMAT_TYPE_AUDIO);
	ast_format_cap_add_all_by_type(multiplexed_bridge.format_capabilities, AST_FORMAT_TYPE_VIDEO);
	ast_format_cap_add_all_by_type(multiplexed_bridge.format_capabilities, AST_FORMAT_TYPE_TEXT);
	return ast_bridge_technology_register(&multiplexed_bridge);
}
コード例 #9
0
static int load_module(void)
{
	if (!(kqueue_timers = ao2_container_alloc(563, kqueue_timer_hash, kqueue_timer_cmp))) {
		return AST_MODULE_LOAD_DECLINE;
	}

	if (!(timing_funcs_handle = ast_register_timing_interface(&kqueue_timing))) {
		ao2_ref(kqueue_timers, -1);
		return AST_MODULE_LOAD_DECLINE;
	}

	AST_TEST_REGISTER(test_kqueue_timing);
	return AST_MODULE_LOAD_SUCCESS;
}
コード例 #10
0
static struct ast_format_cap *cap_alloc_helper(int nolock)
{
	struct ast_format_cap *cap = ast_calloc(1, sizeof(*cap));

	if (!cap) {
		return NULL;
	}
	cap->nolock = nolock ? OBJ_NOLOCK : 0;
	if (!(cap->formats = ao2_container_alloc(283, hash_cb, cmp_cb))) {
		ast_free(cap);
		return NULL;
	}

	return cap;
}
コード例 #11
0
ファイル: threadpool.c プロジェクト: GGGO/asterisk
/*
 * \brief Allocate a threadpool
 *
 * This is implemented as a taskprocessor listener's alloc callback. This
 * is because the threadpool exists as the private data on a taskprocessor
 * listener.
 *
 * \param name The name of the threadpool.
 * \param options The options the threadpool uses.
 * \retval NULL Could not initialize threadpool properly
 * \retval non-NULL The newly-allocated threadpool
 */
static struct ast_threadpool *threadpool_alloc(const char *name, const struct ast_threadpool_options *options)
{
	RAII_VAR(struct ast_threadpool *, pool, NULL, ao2_cleanup);
	struct ast_str *control_tps_name;

	pool = ao2_alloc(sizeof(*pool), threadpool_destructor);
	control_tps_name = ast_str_create(64);
	if (!pool || !control_tps_name) {
		ast_free(control_tps_name);
		return NULL;
	}

	ast_str_set(&control_tps_name, 0, "%s-control", name);

	pool->control_tps = ast_taskprocessor_get(ast_str_buffer(control_tps_name), TPS_REF_DEFAULT);
	ast_free(control_tps_name);
	if (!pool->control_tps) {
		return NULL;
	}
	pool->active_threads = ao2_container_alloc(THREAD_BUCKETS, worker_thread_hash, worker_thread_cmp);
	if (!pool->active_threads) {
		return NULL;
	}
	pool->idle_threads = ao2_container_alloc(THREAD_BUCKETS, worker_thread_hash, worker_thread_cmp);
	if (!pool->idle_threads) {
		return NULL;
	}
	pool->zombie_threads = ao2_container_alloc(THREAD_BUCKETS, worker_thread_hash, worker_thread_cmp);
	if (!pool->zombie_threads) {
		return NULL;
	}
	pool->options = *options;

	ao2_ref(pool, +1);
	return pool;
}
コード例 #12
0
ファイル: resource_events.c プロジェクト: nuecho/asterisk
int ast_ari_websocket_events_event_websocket_init(void)
{
	/* Try to instantiate the registry */
	event_session_registry = ao2_container_alloc(EVENT_SESSION_NUM_BUCKETS,
	                                             event_session_hash,
	                                             event_session_compare);

	if (!event_session_registry) {
		/* This is bad, bad. */
		ast_log(LOG_WARNING,
			    "Failed to allocate the local registry for websocket applications\n");
		return -1;
	}

	return 0;
}
コード例 #13
0
static int load_module(void)
{
	int r;

	r = STASIS_MESSAGE_TYPE_INIT(stasis_app_recording_snapshot_type);
	if (r != 0) {
		return AST_MODULE_LOAD_FAILURE;
	}

	recordings = ao2_container_alloc(RECORDING_BUCKETS, recording_hash,
		recording_cmp);
	if (!recordings) {
		return AST_MODULE_LOAD_FAILURE;
	}
	return AST_MODULE_LOAD_SUCCESS;
}
コード例 #14
0
static int load_module(void)
{
	if (!(pthread_timers = ao2_container_alloc(PTHREAD_TIMER_BUCKETS,
		pthread_timer_hash, pthread_timer_cmp))) {
		return AST_MODULE_LOAD_DECLINE;
	}

	if (init_timing_thread()) {
		ao2_ref(pthread_timers, -1);
		pthread_timers = NULL;
		return AST_MODULE_LOAD_DECLINE;
	}

	return (timing_funcs_handle = ast_register_timing_interface(&pthread_timing)) ?
		AST_MODULE_LOAD_SUCCESS : AST_MODULE_LOAD_DECLINE;
}
コード例 #15
0
ファイル: res_pjsip_mwi.c プロジェクト: adaptiman/asterisk
static struct mwi_subscription *mwi_subscription_alloc(struct ast_sip_endpoint *endpoint,
		unsigned int is_solicited, struct ast_sip_subscription *sip_sub)
{
	struct mwi_subscription *sub;
	const char *endpoint_id = ast_sorcery_object_get_id(endpoint);

	sub = ao2_alloc(sizeof(*sub) + strlen(endpoint_id),
			mwi_subscription_destructor);

	if (!sub) {
		return NULL;
	}

	/* Safe strcpy */
	strcpy(sub->id, endpoint_id);

	/* Unsolicited MWI doesn't actually result in a SIP subscription being
	 * created. This is because a SIP subscription associates with a dialog.
	 * Most devices expect unsolicited MWI NOTIFYs to appear out of dialog. If
	 * they receive an in-dialog MWI NOTIFY (i.e. with a to-tag), then they
	 * will reject the NOTIFY with a 481, thus resulting in message-waiting
	 * state not being updated on the device
	 */
	if (is_solicited) {
		sub->sip_sub = ao2_bump(sip_sub);
	}

	sub->stasis_subs = ao2_container_alloc(STASIS_BUCKETS, stasis_sub_hash, stasis_sub_cmp);
	if (!sub->stasis_subs) {
		ao2_cleanup(sub);
		return NULL;
	}
	sub->is_solicited = is_solicited;

	if (!is_solicited && !ast_strlen_zero(endpoint->aors)) {
		sub->aors = ast_strdup(endpoint->aors);
		if (!sub->aors) {
			ao2_ref(sub, -1);
			return NULL;
		}
	}

	ast_debug(3, "Created %s MWI subscription for endpoint %s\n", is_solicited ? "solicited" : "unsolicited", sub->id);

	return sub;
}
コード例 #16
0
ファイル: res_http_websocket.c プロジェクト: aderbas/asterisk
static struct ast_websocket_server *websocket_server_create_impl(void (*dtor)(void *))
{
	RAII_VAR(struct ast_websocket_server *, server, NULL, ao2_cleanup);

	server = ao2_alloc(sizeof(*server), dtor);
	if (!server) {
		return NULL;
	}

	server->protocols = ao2_container_alloc(MAX_PROTOCOL_BUCKETS, protocol_hash_fn, protocol_cmp_fn);
	if (!server->protocols) {
		return NULL;
	}

	ao2_ref(server, +1);
	return server;
}
コード例 #17
0
static int load_module(void)
{
	const pj_str_t STR_REGISTER = { "REGISTER", 8 };

	if (!(serializers = ao2_container_alloc(
		      SERIALIZER_BUCKETS, serializer_hash, serializer_cmp))) {
		return AST_MODULE_LOAD_DECLINE;
	}

	if (ast_sip_register_service(&registrar_module)) {
		return AST_MODULE_LOAD_DECLINE;
	}

	if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
		ast_sip_unregister_service(&registrar_module);
		return AST_MODULE_LOAD_DECLINE;
	}

	return AST_MODULE_LOAD_SUCCESS;
}
コード例 #18
0
ファイル: stasis.c プロジェクト: GGGO/asterisk
struct stasis_topic_pool *stasis_topic_pool_create(struct stasis_topic *pooled_topic)
{
	struct stasis_topic_pool *pool;

	pool = ao2_alloc_options(sizeof(*pool), topic_pool_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
	if (!pool) {
		return NULL;
	}

	pool->pool_container = ao2_container_alloc(TOPIC_POOL_BUCKETS,
		topic_pool_entry_hash, topic_pool_entry_cmp);
	if (!pool->pool_container) {
		ao2_cleanup(pool);
		return NULL;
	}
	ao2_ref(pooled_topic, +1);
	pool->pool_topic = pooled_topic;

	return pool;
}
コード例 #19
0
ファイル: stasis_cache.c プロジェクト: aderbas/asterisk
struct stasis_cache *stasis_cache_create(snapshot_get_id id_fn)
{
        RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);

        cache = ao2_alloc_options(sizeof(*cache), cache_dtor,
		AO2_ALLOC_OPT_LOCK_NOLOCK);
        if (!cache) {
                return NULL;
        }

        cache->entries = ao2_container_alloc(NUM_CACHE_BUCKETS, cache_entry_hash,
                cache_entry_cmp);
        if (!cache->entries) {
                return NULL;
        }

        cache->id_fn = id_fn;

        ao2_ref(cache, +1);
        return cache;
}
コード例 #20
0
ファイル: stasis_channels.c プロジェクト: jcollie/asterisk
struct ast_multi_channel_blob *ast_multi_channel_blob_create(struct ast_json *blob)
{
	RAII_VAR(struct ast_multi_channel_blob *, obj,
			ao2_alloc(sizeof(*obj), multi_channel_blob_dtor),
			ao2_cleanup);

	ast_assert(blob != NULL);

	if (!obj) {
		return NULL;
	}

	obj->channel_snapshots = ao2_container_alloc(NUM_MULTI_CHANNEL_BLOB_BUCKETS,
			channel_role_hash_cb, channel_role_single_cmp_cb);
	if (!obj->channel_snapshots) {
		return NULL;
	}

	obj->blob = ast_json_ref(blob);

	ao2_ref(obj, +1);
	return obj;
}
コード例 #21
0
static int load_module(void)
{
	int fd;

	/* Make sure we support the necessary clock type */
	if ((fd = timerfd_create(CLOCK_MONOTONIC, 0)) < 0) {
		ast_log(LOG_ERROR, "timerfd_create() not supported by the kernel.  Not loading.\n");
		return AST_MODULE_LOAD_DECLINE;
	}

	close(fd);

	if (!(timerfd_timers = ao2_container_alloc(TIMERFD_TIMER_BUCKETS, timerfd_timer_hash, timerfd_timer_cmp))) {
		return AST_MODULE_LOAD_DECLINE;
	}

	if (!(timing_funcs_handle = ast_register_timing_interface(&timerfd_timing))) {
		ao2_ref(timerfd_timers, -1);
		return AST_MODULE_LOAD_DECLINE;
	}

	return AST_MODULE_LOAD_SUCCESS;
}
コード例 #22
0
struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const char *linkedid, const char *file, int line, const char *function)
{
	struct ast_channel *tmp;
#if defined(REF_DEBUG)
	tmp = __ao2_alloc_debug(sizeof(*tmp), destructor,
		AO2_ALLOC_OPT_LOCK_MUTEX, "", file, line, function, 1);
#elif defined(__AST_DEBUG_MALLOC)
	tmp = __ao2_alloc_debug(sizeof(*tmp), destructor,
		AO2_ALLOC_OPT_LOCK_MUTEX, "", file, line, function, 0);
#else
	tmp = ao2_alloc(sizeof(*tmp), destructor);
#endif

	if ((ast_string_field_init(tmp, 128))) {
		return ast_channel_unref(tmp);
	}

	if (!(tmp->dialed_causes = ao2_container_alloc(DIALED_CAUSES_BUCKETS, pvt_cause_hash_fn, pvt_cause_cmp_fn))) {
		return ast_channel_unref(tmp);
	}

	if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
		ast_channel_uniqueid_build(tmp, "%li.%d", (long)time(NULL),
			ast_atomic_fetchadd_int(&uniqueint, 1));
	} else {
		ast_channel_uniqueid_build(tmp, "%s-%li.%d", ast_config_AST_SYSTEM_NAME,
			(long)time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1));
	}

	if (!ast_strlen_zero(linkedid)) {
		ast_string_field_set(tmp, linkedid, linkedid);
	} else {
		ast_string_field_set(tmp, linkedid, tmp->uniqueid);
	}

	return tmp;
}
コード例 #23
0
ファイル: datastore.c プロジェクト: LorneyZizzart/asterisk
struct ao2_container *ast_datastores_alloc(void)
{
	return ao2_container_alloc(DATASTORE_BUCKETS, ast_datastore_hash_fn, ast_datastore_cmp_fn);
}
コード例 #24
0
static int astobj2_test_helper(int use_hash, int use_cmp, unsigned int lim, struct ast_test *test)
{
	struct ao2_container *c1;
	struct ao2_container *c2;
	struct ao2_iterator it;
	struct test_obj *obj;
	struct test_obj tmp_obj;
	int bucket_size;
	int increment = 0;
	int destructor_count = 0;
	int num;
	int  res = AST_TEST_PASS;

	/* This test needs at least 5 objects */
	if (lim < 5) {
		lim = 5;
	}

	bucket_size = (ast_random() % ((lim / 4) + 1)) + 1;
	c1 = ao2_container_alloc(bucket_size, use_hash ? test_hash_cb : NULL, use_cmp ? test_cmp_cb : NULL);
	c2 = ao2_container_alloc(bucket_size, test_hash_cb, test_cmp_cb);

	if (!c1 || !c2) {
		ast_test_status_update(test, "ao2_container_alloc failed.\n");
		res = AST_TEST_FAIL;
		goto cleanup;
	}

	/* Create objects and link into container */
	destructor_count = lim;
	for (num = 1; num <= lim; num++) {
		if (!(obj = ao2_alloc(sizeof(struct test_obj), test_obj_destructor))) {
			ast_test_status_update(test, "ao2_alloc failed.\n");
			res = AST_TEST_FAIL;
			goto cleanup;
		}
		snprintf(obj->c, sizeof(obj->c), "zombie #%d", num);
		obj->destructor_count = &destructor_count;
		obj->i = num;
		ao2_link(c1, obj);
		ao2_ref(obj, -1);
		if (ao2_container_count(c1) != num) {
			ast_test_status_update(test, "container did not link correctly\n");
			res = AST_TEST_FAIL;
		}
	}

	ast_test_status_update(test, "Container created: random bucket size %d: number of items: %d\n", bucket_size, lim);

	/* Testing ao2_find with no flags */
	num = 100;
	for (; num; num--) {
		int i = (ast_random() % ((lim / 2)) + 1); /* find a random object */
		tmp_obj.i = i;
		if (!(obj = ao2_find(c1, &tmp_obj, 0))) {
			res = AST_TEST_FAIL;
			ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with no flags failed.\n", i);
		} else {
			/* a correct match will only take place when the custom cmp function is used */
			if (use_cmp && obj->i != i) {
				ast_test_status_update(test, "object %d does not match object %d\n", obj->i, tmp_obj.i);
				res = AST_TEST_FAIL;
			}
			ao2_ref(obj, -1);
		}
	}

	/* Testing ao2_find with OBJ_POINTER */
	num = 75;
	for (; num; num--) {
		int i = (ast_random() % ((lim / 2)) + 1); /* find a random object */
		snprintf(tmp_obj.c, sizeof(tmp_obj.c), "zombie #%d", i);
		tmp_obj.i = i;
		if (!(obj = ao2_find(c1, &tmp_obj, OBJ_POINTER))) {
			res = AST_TEST_FAIL;
			ast_test_status_update(test, "COULD NOT FIND:%d, ao2_find() with OBJ_POINTER flag failed.\n", i);
		} else {
			/* a correct match will only take place when the custom cmp function is used */
			if (use_cmp && obj->i != i) {
				ast_test_status_update(test, "object %d does not match object %d\n", obj->i, tmp_obj.i);
				res = AST_TEST_FAIL;
			}
			ao2_ref(obj, -1);
		}
	}

	/* Testing ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE.
	 * In this test items are unlinked from c1 and placed in c2.  Then
	 * unlinked from c2 and placed back into c1.
	 *
	 * For this module and set of custom hash/cmp functions, an object
	 * should only be found if the astobj2 default cmp function is used.
	 * This test is designed to mimic the chan_iax.c call number use case. */
	num = lim < 25 ? lim : 25;
	for (; num; num--) {
		if (!(obj = ao2_find(c1, NULL, OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE))) {
			if (!use_cmp) {
				ast_test_status_update(test, "ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE failed with default hash function.\n");
				res = AST_TEST_FAIL;
			}
		} else {
			if (use_cmp) {
				ast_test_status_update(test, "ao2_find with OBJ_POINTER | OBJ_UNLINK | OBJ_CONTINUE failed with custom hash function.\n");
				res = AST_TEST_FAIL;
			}
			ao2_link(c2, obj);
			ao2_ref(obj, -1);
		}
	}
	it = ao2_iterator_init(c2, 0);
	while ((obj = ao2_iterator_next(&it))) {
		ao2_unlink(c2, obj);
		ao2_link(c1, obj);
		ao2_ref(obj, -1);
	}
	ao2_iterator_destroy(&it);

	/* Test Callback with no flags. */
	increment = 0;
	ao2_callback(c1, 0, increment_cb, &increment);
	if (increment != lim) {
		ast_test_status_update(test, "callback with no flags failed. Increment is %d\n", increment);
		res = AST_TEST_FAIL;
	}

	/* Test Callback with OBJ_NODATA. This should do nothing different than with no flags here. */
	increment = 0;
	ao2_callback(c1, OBJ_NODATA, increment_cb, &increment);
	if (increment != lim) {
		ast_test_status_update(test, "callback with OBJ_NODATA failed. Increment is %d\n", increment);
		res = AST_TEST_FAIL;
	}

	/* Is the container count what we expect after all the finds and unlinks?*/
	if (ao2_container_count(c1) != lim) {
		ast_test_status_update(test, "container count does not match what is expected after ao2_find tests.\n");
		res = AST_TEST_FAIL;
	}

	/* Testing iterator.  Unlink a single object and break. do not add item back */
	it = ao2_iterator_init(c1, 0);
	num = (lim / 4) + 1;
	while ((obj = ao2_iterator_next(&it))) {
		if (obj->i == num) {
			ao2_ref(obj, -1);
			ao2_unlink(c1, obj);
			break;
		}
		ao2_ref(obj, -1);
	}
	ao2_iterator_destroy(&it);

	/* Is the container count what we expect after removing a single item? */
	if (ao2_container_count(c1) != (lim - 1)) {
		ast_test_status_update(test, "unlink during iterator failed. Number %d was not removed.\n", num);
		res = AST_TEST_FAIL;
	}

	/* Test unlink all with OBJ_MULTIPLE, leave a single object for the container to destroy */
	ao2_callback(c1, OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA, all_but_one_cb, NULL);
	/* check to make sure all test_obj destructors were called except for 1 */
	if (destructor_count != 1) {
		ast_test_status_update(test, "OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NODATA failed. destructor count %d\n", destructor_count);
		res = AST_TEST_FAIL;
	}

cleanup:
	/* destroy containers */
	if (c1) {
		ao2_ref(c1, -1);
	}
	if (c2) {
		ao2_ref(c2, -1);
	}

	if (destructor_count > 0) {
		ast_test_status_update(test, "all destructors were not called, destructor count is %d\n", destructor_count);
		res = AST_TEST_FAIL;
	} else if (destructor_count < 0) {
		ast_test_status_update(test, "Destructor was called too many times, destructor count is %d\n", destructor_count);
		res = AST_TEST_FAIL;
	}

	return res;
}