static struct stasis_message_router *stasis_message_router_create_internal( struct stasis_topic *topic, int use_thread_pool) { int res; RAII_VAR(struct stasis_message_router *, router, NULL, ao2_cleanup); router = ao2_t_alloc(sizeof(*router), router_dtor, stasis_topic_name(topic)); if (!router) { return NULL; } res = 0; res |= AST_VECTOR_INIT(&router->routes, 0); res |= AST_VECTOR_INIT(&router->cache_routes, 0); if (res) { return NULL; } if (use_thread_pool) { router->subscription = stasis_subscribe_pool(topic, router_dispatch, router); } else { router->subscription = stasis_subscribe(topic, router_dispatch, router); } if (!router->subscription) { return NULL; } ao2_ref(router, +1); return router; }
struct stasis_subscription *internal_stasis_subscribe( struct stasis_topic *topic, stasis_subscription_cb callback, void *data, int needs_mailbox, int use_thread_pool) { RAII_VAR(struct stasis_subscription *, sub, NULL, ao2_cleanup); if (!topic) { return NULL; } /* The ao2 lock is used for join_cond. */ sub = ao2_t_alloc(sizeof(*sub), subscription_dtor, stasis_topic_name(topic)); if (!sub) { return NULL; } ast_uuid_generate_str(sub->uniqueid, sizeof(sub->uniqueid)); if (needs_mailbox) { char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1]; /* Create name with seq number appended. */ ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "sub%c:%s", use_thread_pool ? 'p' : 'm', stasis_topic_name(topic)); /* * With a small number of subscribers, a thread-per-sub is * acceptable. For a large number of subscribers, a thread * pool should be used. */ if (use_thread_pool) { sub->mailbox = ast_threadpool_serializer(tps_name, pool); } else { sub->mailbox = ast_taskprocessor_get(tps_name, TPS_REF_DEFAULT); } if (!sub->mailbox) { return NULL; } ast_taskprocessor_set_local(sub->mailbox, sub); /* Taskprocessor has a reference */ ao2_ref(sub, +1); } ao2_ref(topic, +1); sub->topic = topic; sub->callback = callback; sub->data = data; ast_cond_init(&sub->join_cond, NULL); if (topic_add_subscription(topic, sub) != 0) { return NULL; } send_subscription_subscribe(topic, sub); ao2_ref(sub, +1); return sub; }
/*! \brief Publish a Corosync ping to \ref stasis */ static void publish_corosync_ping_to_stasis(struct ast_event *event) { struct corosync_ping_payload *payload; struct stasis_message *message; ast_assert(ast_event_get_type(event) == AST_EVENT_PING); ast_assert(event != NULL); if (!corosync_ping_message_type()) { return; } payload = ao2_t_alloc(sizeof(*payload), corosync_ping_payload_dtor, "Create ping payload"); if (!payload) { return; } payload->event = event; message = stasis_message_create(corosync_ping_message_type(), payload); if (!message) { ao2_t_ref(payload, -1, "Destroy payload on off nominal"); return; } stasis_publish(corosync_topic(), message); ao2_t_ref(payload, -1, "Hand ref to stasis"); ao2_t_ref(message, -1, "Hand ref to stasis"); }
struct stasis_cp_all *stasis_cp_all_create(const char *name, snapshot_get_id id_fn) { char *cached_name = NULL; struct stasis_cp_all *all; static int cache_id; all = ao2_t_alloc(sizeof(*all), all_dtor, name); if (!all) { return NULL; } ast_asprintf(&cached_name, "cache_pattern:%d/%s", ast_atomic_fetchadd_int(&cache_id, +1), name); if (!cached_name) { ao2_ref(all, -1); return NULL; } all->topic = stasis_topic_create(name); all->topic_cached = stasis_topic_create(cached_name); ast_free(cached_name); all->cache = stasis_cache_create(id_fn); all->forward_all_to_cached = stasis_forward_all(all->topic, all->topic_cached); if (!all->topic || !all->topic_cached || !all->cache || !all->forward_all_to_cached) { ao2_ref(all, -1); return NULL; } return all; }
struct stasis_cp_single *stasis_cp_sink_create(struct stasis_cp_all *all, const char *name) { struct stasis_cp_single *one; one = ao2_t_alloc(sizeof(*one), one_dtor, name); if (!one) { return NULL; } one->topic = stasis_topic_create(name); if (!one->topic) { ao2_ref(one, -1); return NULL; } one->topic_cached = stasis_caching_topic_create(one->topic, all->cache); if (!one->topic_cached) { ao2_ref(one, -1); return NULL; } return one; }
struct stasis_cp_all *stasis_cp_all_create(const char *name, snapshot_get_id id_fn) { RAII_VAR(char *, cached_name, NULL, ast_free); RAII_VAR(struct stasis_cp_all *, all, NULL, ao2_cleanup); all = ao2_t_alloc(sizeof(*all), all_dtor, name); if (!all) { return NULL; } ast_asprintf(&cached_name, "%s-cached", name); if (!cached_name) { return NULL; } all->topic = stasis_topic_create(name); all->topic_cached = stasis_topic_create(cached_name); all->cache = stasis_cache_create(id_fn); all->forward_all_to_cached = stasis_forward_all(all->topic, all->topic_cached); if (!all->topic || !all->topic_cached || !all->cache || !all->forward_all_to_cached) { return NULL; } ao2_ref(all, +1); return all; }
struct stasis_cp_single *stasis_cp_single_create(struct stasis_cp_all *all, const char *name) { RAII_VAR(struct stasis_cp_single *, one, NULL, ao2_cleanup); one = ao2_t_alloc(sizeof(*one), one_dtor, name); if (!one) { return NULL; } one->topic = stasis_topic_create(name); if (!one->topic) { return NULL; } one->topic_cached = stasis_caching_topic_create(one->topic, all->cache); if (!one->topic_cached) { return NULL; } one->forward_topic_to_all = stasis_forward_all(one->topic, all->topic); if (!one->forward_topic_to_all) { return NULL; } one->forward_cached_to_all = stasis_forward_all( stasis_caching_get_topic(one->topic_cached), all->topic_cached); if (!one->forward_cached_to_all) { return NULL; } ao2_ref(one, +1); return one; }
struct stasis_subscription *internal_stasis_subscribe( struct stasis_topic *topic, stasis_subscription_cb callback, void *data, int needs_mailbox, int use_thread_pool) { RAII_VAR(struct stasis_subscription *, sub, NULL, ao2_cleanup); if (!topic) { return NULL; } /* The ao2 lock is used for join_cond. */ sub = ao2_t_alloc(sizeof(*sub), subscription_dtor, topic->name); if (!sub) { return NULL; } ast_uuid_generate_str(sub->uniqueid, sizeof(sub->uniqueid)); if (needs_mailbox) { /* With a small number of subscribers, a thread-per-sub is * acceptable. For larger number of subscribers, a thread * pool should be used. */ if (use_thread_pool) { sub->mailbox = ast_threadpool_serializer(sub->uniqueid, pool); } else { sub->mailbox = ast_taskprocessor_get(sub->uniqueid, TPS_REF_DEFAULT); } if (!sub->mailbox) { return NULL; } ast_taskprocessor_set_local(sub->mailbox, sub); /* Taskprocessor has a reference */ ao2_ref(sub, +1); } ao2_ref(topic, +1); sub->topic = topic; sub->callback = callback; sub->data = data; ast_cond_init(&sub->join_cond, NULL); if (topic_add_subscription(topic, sub) != 0) { return NULL; } send_subscription_subscribe(topic, sub); ao2_ref(sub, +1); return sub; }
/*! * \internal * \brief Create the scheduling data object. */ static struct sched_data *sched_data_create(struct ast_sip_contact *contact) { struct sched_data *data; data = ao2_t_alloc(sizeof(*data), sched_data_destructor, contact->uri); if (!data) { ast_log(LOG_ERROR, "Unable to create schedule qualify data for contact %s\n", contact->uri); return NULL; } data->contact = contact; ao2_ref(data->contact, +1); return data; }
static struct app_forwards *forwards_create(struct stasis_app *app, const char *id) { struct app_forwards *forwards; if (!app || ast_strlen_zero(id)) { return NULL; } forwards = ao2_t_alloc(sizeof(*forwards) + strlen(id) + 1, forwards_dtor, id); if (!forwards) { return NULL; } strcpy(forwards->id, id); /* SAFE */ return forwards; }
struct stasis_topic *stasis_topic_create(const char *name) { struct stasis_topic *topic; int res = 0; topic = ao2_t_alloc(sizeof(*topic), topic_dtor, name); if (!topic) { return NULL; } topic->name = ast_strdup(name); res |= AST_VECTOR_INIT(&topic->subscribers, INITIAL_SUBSCRIBERS_MAX); res |= AST_VECTOR_INIT(&topic->upstream_topics, 0); if (!topic->name || res) { ao2_cleanup(topic); return NULL; } return topic; }
/* * This is testing code for astobj */ static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { struct ao2_container *c1; struct ao2_container *c2; int i, lim; char *obj; static int prof_id = -1; struct ast_cli_args fake_args = { a->fd, 0, NULL }; switch (cmd) { case CLI_INIT: e->command = "astobj2 test"; e->usage = "Usage: astobj2 test <num>\n" " Runs astobj2 test. Creates 'num' objects,\n" " and test iterators, callbacks and maybe other stuff\n"; return NULL; case CLI_GENERATE: return NULL; } if (a->argc != 3) { return CLI_SHOWUSAGE; } if (prof_id == -1) { prof_id = ast_add_profile("ao2_alloc", 0); } ast_cli(a->fd, "argc %d argv %s %s %s\n", a->argc, a->argv[0], a->argv[1], a->argv[2]); lim = atoi(a->argv[2]); ast_cli(a->fd, "called astobj_test\n"); handle_astobj2_stats(e, CLI_HANDLER, &fake_args); /* * Allocate a list container. */ c1 = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX, 0, NULL /* no sort */, NULL /* no callback */, "test"); ast_cli(a->fd, "container allocated as %p\n", c1); /* * fill the container with objects. * ao2_alloc() gives us a reference which we pass to the * container when we do the insert. */ for (i = 0; i < lim; i++) { ast_mark(prof_id, 1 /* start */); obj = ao2_t_alloc(80, NULL,"test"); ast_mark(prof_id, 0 /* stop */); ast_cli(a->fd, "object %d allocated as %p\n", i, obj); sprintf(obj, "-- this is obj %d --", i); ao2_link(c1, obj); /* At this point, the refcount on obj is 2 due to the allocation * and linking. We can go ahead and reduce the refcount by 1 * right here so that when the container is unreffed later, the * objects will be freed */ ao2_t_ref(obj, -1, "test"); } ast_cli(a->fd, "testing callbacks\n"); ao2_t_callback(c1, 0, print_cb, a, "test callback"); ast_cli(a->fd, "testing container cloning\n"); c2 = ao2_container_clone(c1, 0); if (ao2_container_count(c1) != ao2_container_count(c2)) { ast_cli(a->fd, "Cloned container does not have the same number of objects!\n"); } ao2_t_callback(c2, 0, print_cb, a, "test callback"); ast_cli(a->fd, "testing iterators, remove every second object\n"); { struct ao2_iterator ai; int x = 0; ai = ao2_iterator_init(c1, 0); while ( (obj = ao2_t_iterator_next(&ai,"test")) ) { ast_cli(a->fd, "iterator on <%s>\n", obj); if (x++ & 1) ao2_t_unlink(c1, obj,"test"); ao2_t_ref(obj, -1,"test"); } ao2_iterator_destroy(&ai); ast_cli(a->fd, "testing iterators again\n"); ai = ao2_iterator_init(c1, 0); while ( (obj = ao2_t_iterator_next(&ai,"test")) ) { ast_cli(a->fd, "iterator on <%s>\n", obj); ao2_t_ref(obj, -1,"test"); } ao2_iterator_destroy(&ai); } ast_cli(a->fd, "testing callbacks again\n"); ao2_t_callback(c1, 0, print_cb, a, "test callback"); ast_verbose("now you should see an error and possible assertion failure messages:\n"); ao2_t_ref(&i, -1, ""); /* i is not a valid object so we print an error here */ ast_cli(a->fd, "destroy container\n"); ao2_t_ref(c1, -1, ""); /* destroy container */ ao2_t_ref(c2, -1, ""); /* destroy container */ handle_astobj2_stats(e, CLI_HANDLER, &fake_args); return CLI_SUCCESS; }