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; }
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; }
/*! * \brief Add a subscriber to a topic. * \param topic Topic * \param sub Subscriber * \return 0 on success * \return Non-zero on error */ static int topic_add_subscription(struct stasis_topic *topic, struct stasis_subscription *sub) { size_t idx; SCOPED_AO2LOCK(lock, topic); /* The reference from the topic to the subscription is shared with * the owner of the subscription, which will explicitly unsubscribe * to release it. * * If we bumped the refcount here, the owner would have to unsubscribe * and cleanup, which is a bit awkward. */ AST_VECTOR_APPEND(&topic->subscribers, sub); for (idx = 0; idx < AST_VECTOR_SIZE(&topic->upstream_topics); ++idx) { topic_add_subscription( AST_VECTOR_GET(&topic->upstream_topics, idx), sub); } return 0; }
struct stasis_forward *stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic) { int res; size_t idx; RAII_VAR(struct stasis_forward *, forward, NULL, ao2_cleanup); if (!from_topic || !to_topic) { return NULL; } forward = ao2_alloc_options(sizeof(*forward), forward_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK); if (!forward) { return NULL; } /* Forwards to ourselves are implicit. */ if (to_topic == from_topic) { return ao2_bump(forward); } forward->from_topic = ao2_bump(from_topic); forward->to_topic = ao2_bump(to_topic); topic_lock_both(to_topic, from_topic); res = AST_VECTOR_APPEND(&to_topic->upstream_topics, from_topic); if (res != 0) { ao2_unlock(from_topic); ao2_unlock(to_topic); return NULL; } for (idx = 0; idx < AST_VECTOR_SIZE(&to_topic->subscribers); ++idx) { topic_add_subscription(from_topic, AST_VECTOR_GET(&to_topic->subscribers, idx)); } ao2_unlock(from_topic); ao2_unlock(to_topic); return ao2_bump(forward); }