[asterisk-commits] dlee: branch dlee/stasis-app r381838 - in /team/dlee/stasis-app: apps/ includ...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Feb 20 14:23:49 CST 2013


Author: dlee
Date: Wed Feb 20 14:23:46 2013
New Revision: 381838

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=381838
Log:
Split app and control structs

Modified:
    team/dlee/stasis-app/apps/app_stasis.c
    team/dlee/stasis-app/include/asterisk/app_stasis.h

Modified: team/dlee/stasis-app/apps/app_stasis.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/apps/app_stasis.c?view=diff&rev=381838&r1=381837&r2=381838
==============================================================================
--- team/dlee/stasis-app/apps/app_stasis.c (original)
+++ team/dlee/stasis-app/apps/app_stasis.c Wed Feb 20 14:23:46 2013
@@ -72,11 +72,19 @@
 #define APPS_NUM_BUCKETS 127
 
 /*!
+ * \brief Number of buckets for the Stasis application hash table.  Remember to
+ * keep it a prime number!
+ */
+#define CONTROLS_NUM_BUCKETS 127
+
+/*!
  * \brief Stasis application container. Please call stasis_apps() instead of
  * directly accessing.
  */
 struct ao2_container *__stasis_apps;
 
+struct ao2_container *__stasis_controls;
+
 /*! Ref-counting accessor for the stasis applications container */
 static struct ao2_container *stasis_apps(void)
 {
@@ -84,7 +92,12 @@
 	return __stasis_apps;
 }
 
-/*! \brief Stasis application ref */
+static struct ao2_container *stasis_contols(void)
+{
+	ao2_ref(__stasis_controls, +1);
+	return __stasis_controls;
+}
+
 struct stasis_app {
 	/*! Name of the Stasis application */
 	char *name;
@@ -92,69 +105,115 @@
 	stasis_app_cb handler;
 	/*! Opaque data to hand to callback function. */
 	void *data;
+};
+
+/*! Destructor for \ref stasis_app. */
+static void app_dtor(void *obj)
+{
+	struct stasis_app *app = obj;
+	ast_free(app->name);
+}
+
+/*! Constructor for \ref stasis_app. */
+static struct stasis_app *app_create(const char *name, stasis_app_cb handler, void *data)
+{
+	RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
+
+	ast_assert(name != NULL);
+	ast_assert(handler != NULL);
+
+	app = ao2_alloc_options(sizeof(*app), app_dtor, AO2_ALLOC_OPT_LOCK_MUTEX);
+
+	if (!app) {
+		return NULL;
+	}
+
+	if (!(app->name = ast_strdup(name))) {
+		return NULL;
+	}
+
+	app->handler = handler;
+	app->data = data;
+
+	ao2_ref(app, +1);
+	return app;
+}
+
+/*! AO2 hash function for \ref stasis_app */
+static int app_hash(const void *obj, const int flags)
+{
+	const struct stasis_app *app = obj;
+	const char *name = flags & OBJ_KEY ? obj : app->name;
+
+	return ast_hashtab_hash_string(name);
+}
+
+/*! AO2 comparison function for \ref stasis_app */
+static int app_compare(void *lhs, void *rhs, int flags)
+{
+	const struct stasis_app *lhs_app = lhs;
+	const struct stasis_app *rhs_app = rhs;
+	const char *rhs_name = flags & OBJ_KEY ? rhs : rhs_app->name;
+
+	if (strcmp(lhs_app->name, rhs_name) == 0) {
+		return CMP_MATCH | CMP_STOP;
+	} else {
+		return 0;
+	}
+}
+
+/*!
+ * \brief Send a message to the given application.
+ * \param app App to send the message to.
+ * \param message Message to send.
+ */
+static void app_send(struct stasis_app *app, struct ast_json *message)
+{
+	app->handler(app->data, app->name, message);
+}
+
+struct stasis_app_control {
+	/*! Uniqueid of the associated channel */
+	char *channel_uniqueid;
 	/*!
 	 * When set, /c app_stasis should exit and continue in the dialplan.
 	 */
 	int continue_to_dialplan:1;
-	/*!
-	 * When set, indicates \c app_stasis is currently running.
-	 */
-	int is_in_app_stasis:1;
 };
 
-/*! Destructor for \ref stasis_app. */
-static void app_dtor(void *obj)
-{
-	struct stasis_app *app = obj;
-	ast_free(app->name);
-}
-
-/*! Constructor for \ref stasis_app. */
-static struct stasis_app *app_create(const char *name, stasis_app_cb handler, void *data)
-{
-	RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
-
-	ast_assert(name != NULL);
-	ast_assert(handler != NULL);
-
-	app = ao2_alloc_options(sizeof(*app), app_dtor, AO2_ALLOC_OPT_LOCK_MUTEX);
-
-	if (!app) {
-		return NULL;
-	}
-
-	if (!(app->name = ast_strdup(name))) {
-		return NULL;
-	}
-
-	app->handler = handler;
-	app->data = data;
-
-	ao2_ref(app, +1);
-	return app;
-}
-
-/*! AO2 hash function for \ref stasis_app */
-static int app_hash(const void *obj, const int flags)
-{
-	const struct stasis_app *app = obj;
-	const char *name = flags & OBJ_KEY ? obj : app->name;
-
-	return ast_hashtab_hash_string(name);
-}
-
-/*! AO2 comparison function for \ref stasis_app */
-static int app_compare(void *lhs, void *rhs, int flags)
-{
-	const struct stasis_app *lhs_app = lhs;
-	const struct stasis_app *rhs_app = rhs;
-	const char *rhs_name = flags & OBJ_KEY ? rhs : rhs_app->name;
-
-	if (strcmp(lhs_app->name, rhs_name) == 0) {
-		return CMP_MATCH | CMP_STOP;
-	} else {
-		return 0;
-	}
+static void stasis_app_control_dtor(void *obj)
+{
+	struct stasis_app_control *control = obj;
+	ast_free(control->channel_uniqueid);
+}
+
+static struct stasis_app_control *control_create(const char *uniqueid)
+{
+	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+	control = ao2_alloc(sizeof(*control), stasis_app_control_dtor);
+	if (!control) {
+		return NULL;
+	}
+
+	control->channel_uniqueid = ast_strdup(uniqueid);
+	if (!control->channel_uniqueid) {
+		return NULL;
+	}
+
+	ao2_ref(control, +1);
+	return control;
+}
+
+struct stasis_app_control *stasis_app_control_find_by_channel(const struct ast_channel *chan)
+{
+	RAII_VAR(struct ao2_container *, controls, NULL, ao2_cleanup);
+	if (chan == NULL) {
+		return NULL;
+	}
+
+	controls = stasis_contols();
+	return ao2_find(controls, ast_channel_uniqueid(chan), OBJ_KEY);
 }
 
 /*!
@@ -166,56 +225,20 @@
  * \return Zero to remain in \c Stasis
  * \return Non-zero to continue in the dialplan
  */
-static int app_continue_test_and_reset(struct stasis_app *app)
-{
-	int r;
-	SCOPED_AO2LOCK(lock, app);
-
-	r = app->continue_to_dialplan;
-	app->continue_to_dialplan = 0;
-	return r;
-}
-
-/*!
- * \brief Atomically set the is_in_app_stasis flag on an \a app.
- * \param app Application to put into stasis
- * \param is_in_app_stasis New value of is_in_app_stasis
- */
-static void app_set_is_in_app_stasis(struct stasis_app *app, int is_in_app_stasis)
-{
-	if (app) {
-		SCOPED_AO2LOCK(lock, app);
-		app->is_in_app_stasis = is_in_app_stasis;
-	}
-}
-
-/*!
- * \brief Send a message to the given application.
- * \param app App to send the message to.
- * \param message Message to send.
- */
-static void app_send(struct stasis_app *app, struct ast_json *message)
-{
-	app->handler(app->data, app->name, message);
-}
-
-struct stasis_app *stasis_app_find_by_channel(struct ast_channel *chan)
-{
-	RAII_VAR(struct ao2_container *, handlers, NULL, ao2_cleanup);
-	if (chan == NULL) {
-		return NULL;
-	}
-
-	handlers = stasis_apps();
-	return ao2_find(handlers, ast_channel_uniqueid(chan), OBJ_KEY);
-}
-
-void stasis_app_continue(struct stasis_app *handler)
-{
-	SCOPED_AO2LOCK(lock, handler);
-	if (handler->is_in_app_stasis) {
-		handler->continue_to_dialplan = 1;
-	}
+static int control_continue_test_and_reset(struct stasis_app_control *control)
+{
+        int r;
+        SCOPED_AO2LOCK(lock, control);
+
+        r = control->continue_to_dialplan;
+        control->continue_to_dialplan = 0;
+        return r;
+}
+
+void stasis_app_control_continue(struct stasis_app_control *control)
+{
+	SCOPED_AO2LOCK(lock, control);
+	control->continue_to_dialplan = 1;
 }
 
 struct ast_json *stasis_app_event_create(const char *event_name, const struct ast_channel_snapshot *channel_info, const struct ast_json *extra_info) {
@@ -323,16 +346,17 @@
 }
 
 /*!
- * \brief RAII_VAR dtor, which unsets \c is_in_app_stasis in addition to
- * ao2_cleanup().
- * \param obj \ref stasis_app object to clean up.
- */
-static void app_unset_and_cleanup(void *obj)
-{
-	struct stasis_app *app = obj;
-	if (obj) {
-		app_set_is_in_app_stasis(app, 0);
-		ao2_cleanup(obj);
+ * \brief In addition to running ao2_cleanup(), this function also removes the
+ * object from the stasis_controls() container.
+ */
+static void control_unlink(struct stasis_app_control *control)
+{
+	RAII_VAR(struct ao2_container *, controls, NULL, ao2_cleanup);
+
+	if (control) {
+		controls = stasis_contols();
+		ao2_unlink_flags(controls, control, OBJ_POINTER | OBJ_UNLINK | OBJ_NODATA);
+		ao2_cleanup(control);
 	}
 }
 
@@ -340,7 +364,8 @@
 static int stasis_exec(struct ast_channel *chan, const char *data)
 {
 	RAII_VAR(struct ao2_container *, apps, stasis_apps(), ao2_cleanup);
-	RAII_VAR(struct stasis_app *, app, NULL, app_unset_and_cleanup);
+	RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
+	RAII_VAR(struct stasis_app_control *, control, NULL, control_unlink);
 	RAII_VAR(struct stasis_subscription *, subscription, NULL, stasis_unsubscribe);
 	int res = 0;
 	char *parse = NULL;
@@ -364,16 +389,24 @@
 	}
 
 	app = ao2_find(apps, args.app_name, OBJ_KEY);
-
 	if (!app) {
 		ast_log(LOG_ERROR, "Stasis app '%s' not registered\n", args.app_name);
 		return -1;
 	}
 
-	app_set_is_in_app_stasis(app, 1);
+	{
+		RAII_VAR(struct ao2_container *, controls, NULL, ao2_cleanup);
+
+		controls = stasis_contols();
+		control = control_create(ast_channel_uniqueid(chan));
+		if (!control) {
+			ast_log(LOG_ERROR, "Allocated failed\n");
+			return -1;
+		}
+		ao2_link(controls, control);
+	}
 
 	subscription = stasis_subscribe(ast_channel_events(chan), sub_handler, app);
-
 	if (subscription == NULL) {
 		ast_log(LOG_ERROR, "Error subscribing app %s to channel %s\n", args.app_name, ast_channel_name(chan));
 		return -1;
@@ -385,7 +418,7 @@
 		return res;
 	}
 
-	while (!hungup && !app_continue_test_and_reset(app) && ast_waitfor(chan, -1) > -1) {
+	while (!hungup && !control_continue_test_and_reset(control) && ast_waitfor(chan, -1) > -1) {
 		RAII_VAR(struct ast_frame *, f, ast_read(chan), ast_frame_dtor);
 		if (!f) {
 			ast_debug(3, "%s: No more frames. Must be done, I guess.\n", ast_channel_uniqueid(chan));
@@ -480,6 +513,11 @@
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
+	__stasis_controls = ao2_container_alloc(CONTROLS_NUM_BUCKETS, app_hash, app_compare);
+	if (__stasis_controls == NULL) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+
 	r |= ast_register_application_xml(stasis, stasis_exec);
 	return r;
 }
@@ -490,6 +528,9 @@
 
 	ao2_cleanup(__stasis_apps);
 	__stasis_apps = NULL;
+
+	ao2_cleanup(__stasis_controls);
+	__stasis_controls = NULL;
 
 	r |= ast_unregister_application(stasis);
 	return r;

Modified: team/dlee/stasis-app/include/asterisk/app_stasis.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-app/include/asterisk/app_stasis.h?view=diff&rev=381838&r1=381837&r2=381838
==============================================================================
--- team/dlee/stasis-app/include/asterisk/app_stasis.h (original)
+++ team/dlee/stasis-app/include/asterisk/app_stasis.h Wed Feb 20 14:23:46 2013
@@ -32,7 +32,9 @@
 #include "asterisk/channel.h"
 #include "asterisk/json.h"
 
-/*! \brief Handler for controlling app_stasis */
+/*! @{ */
+
+/*! \brief Handler for a registered Stasis applicatoin. */
 struct stasis_app;
 
 /*!
@@ -47,23 +49,6 @@
  * \return -1 for error.
  */
 int stasis_app_send(const char *app_name, struct ast_json *message);
-
-/*!
- * \brief Returns the handler for the given channel
- * \param chan Channel to handle.
- * \return NULL channel not in Stasis application
- * \return Pointer to app_stasis handler.
- */
-struct stasis_app *stasis_app_find_by_channel(struct ast_channel *chan);
-
-/*!
- * \brief Exit \c app_stasis and continue execution in the dialplan.
- *
- * If the channel is no longer in \c app_stasis, this function does nothing.
- *
- * \param handler Handler for \c app_stasis
- */
-void stasis_app_continue(struct stasis_app *handler);
 
 /*!
  * \brief Callback for Stasis application handler.
@@ -95,6 +80,34 @@
  */
 void stasis_app_unregister(const char *app_name);
 
+/*! @} */
+
+/*! @{ */
+
+/*! \brief Handler for controlling a channel that's in a Stasis application */
+struct stasis_app_control;
+
+/*!
+ * \brief Returns the handler for the given channel
+ * \param chan Channel to handle.
+ * \return NULL channel not in Stasis application
+ * \return Pointer to app_stasis handler.
+ */
+struct stasis_app_control *stasis_app_control_find_by_channel(const struct ast_channel *chan);
+
+/*!
+ * \brief Exit \c app_stasis and continue execution in the dialplan.
+ *
+ * If the channel is no longer in \c app_stasis, this function does nothing.
+ *
+ * \param handler Handler for \c app_stasis
+ */
+void stasis_app_control_continue(struct stasis_app_control *handler);
+
+/*! @} */
+
+/*! @{ */
+
 /*!
  * \brief Build a JSON object from a \ref ast_channel_snapshot.
  * \return JSON object representing channel snapshot.
@@ -112,4 +125,6 @@
  */
 struct ast_json *stasis_app_event_create(const char *event_name, const struct ast_channel_snapshot *channel_info, const struct ast_json *extra_info);
 
+/*! @} */
+
 #endif /* _ASTERISK_APP_STASIS_H */




More information about the asterisk-commits mailing list