[asterisk-commits] dlee: branch dlee/ASTERISK-22243 r396355 - in /team/dlee/ASTERISK-22243: cont...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Aug 7 10:11:09 CDT 2013


Author: dlee
Date: Wed Aug  7 10:11:07 2013
New Revision: 396355

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=396355
Log:
Comments

Modified:
    team/dlee/ASTERISK-22243/contrib/asterisk-ng-doxygen
    team/dlee/ASTERISK-22243/main/stasis.c

Modified: team/dlee/ASTERISK-22243/contrib/asterisk-ng-doxygen
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22243/contrib/asterisk-ng-doxygen?view=diff&rev=396355&r1=396354&r2=396355
==============================================================================
--- team/dlee/ASTERISK-22243/contrib/asterisk-ng-doxygen (original)
+++ team/dlee/ASTERISK-22243/contrib/asterisk-ng-doxygen Wed Aug  7 10:11:07 2013
@@ -34,7 +34,7 @@
 # This could be handy for archiving the generated documentation or
 # if some version control system is used.
 
-PROJECT_NUMBER         = SVN-dlee-ASTERISK-22243-URL:-r396345M-/trunk
+PROJECT_NUMBER         = SVN-dlee-ASTERISK-22243-URL:-r396348M-/trunk
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer

Modified: team/dlee/ASTERISK-22243/main/stasis.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ASTERISK-22243/main/stasis.c?view=diff&rev=396355&r1=396354&r2=396355
==============================================================================
--- team/dlee/ASTERISK-22243/main/stasis.c (original)
+++ team/dlee/ASTERISK-22243/main/stasis.c Wed Aug  7 10:11:07 2013
@@ -45,9 +45,8 @@
  * \par Reference counting
  *
  * Stasis introduces a number of objects, which are tightly related to one
- * another. Since C relies on manual memory management, and we rely on
- * ref-counting, understanding these relationships is important to understanding
- * this code.
+ * another. Because we rely on ref-counting for memory management, understanding
+ * these relationships is important to understanding this code.
  *
  * \code{.txt}
  *
@@ -72,16 +71,20 @@
  * necessary. Topics need the subscription in order to dispatch messages;
  * subscriptions need the topics to unsubscribe and check subscription status.
  *
- * To balance the cycle, the reference from the subscription to the topic is
- * considered the 'master', and the topic does _not_ bump the refcount on the
- * subscription. A topic will not be destroyed until it has no subscribers.
- *
- * The dispatch object is a transient object, which is mailed to a
- * subscription's taskprocessor to send a message to the subscriber. They tend
- * to have short and fast life cycles, allocated on one thread, destroyed on
- * another.
- *
- * During shutdown, or the deletion of objects, there are a flurry of
+ * The cycle is broken by stasis_unsubscribe(). The unsubscribe will remove the
+ * topic's reference to a subscription. When the subcription is destroyed, it
+ * will remove its reference to the topic.
+ *
+ * This means that until a subscription has be explicitly unsubscribed, it will
+ * not be destroyed. Neither will a topic be destroyed while it has subscribers.
+ * The destructors of both have assertions regarding this to catch ref-counting
+ * problems where a subscription or topic has had an extra ao2_cleanup().
+ *
+ * The \ref dispatch object is a transient object, which is posted to a
+ * subscription's taskprocessor to send a message to the subscriber. They have
+ * short life cycles, allocated on one thread, destroyed on another.
+ *
+ * During shutdown, or the deletion of a domain object, there are a flurry of
  * ao2_cleanup()s on subscriptions and topics, as the final in-flight messages
  * are processed. Any one of these cleanups could be the one to actually destroy
  * a given object, so care must be taken to ensure that an object isn't
@@ -95,15 +98,19 @@
  *      are actually fed by shorter-lived topics whose lifetime is associated
  *      with some domain object (like ast_channel_topic() for a given
  *      ast_channel).
+ *
  *  \li stasis_subscription - Subscriptions have a similar mix of lifetimes as
  *      topics, for similar reasons.
+ *
  *  \li dispatch - Very short lived; just long enough to post a message to a
  *      subscriber.
+ *
  *  \li stasis_message - Short to intermediate lifetimes, but that is mostly
  *      irrelevant. Messages are strictly data and have no behavior associated
- *      with them, so it doesn't really matter if/when/how they are destroyed.
- *      By design, some component could hold a ref to a message forever without
- *      any ill consequences (aside from consuming more memory).
+ *      with them, so it doesn't really matter if/when they are destroyed. By
+ *      design, a component could hold a ref to a message forever without any
+ *      ill consequences (aside from consuming more memory).
+ *
  *  \li stasis_message_type - Long life cycles, typically only destroyed on
  *      module unloading or _clean_ process exit.
  *
@@ -112,6 +119,13 @@
  * Subscribers are sensitive to shutdown sequencing, specifically in how the
  * reference message types. This is fully detailed on the wiki at
  * https://wiki.asterisk.org/wiki/x/K4BqAQ.
+ *
+ * In short, the lifetime of the \a data (and \a callback, if in a module) must
+ * be held until the stasis_subscription_final_message() has been received.
+ * Depending on the structure of the subscriber code, this can be handled by
+ * using stasis_subscription_final_message() to free resources on the final
+ * message, or using stasis_subscription_join()/stasis_unsubscribe_and_join() to
+ * block until the unsubscribe has completed.
  */
 
 /*! Initial size of the subscribers list. */
@@ -128,7 +142,7 @@
 /*! \internal */
 struct stasis_topic {
 	char *name;
-	/*! Variable length array of the subscribers. */
+	/*! Variable length array of the subscribers */
 	struct stasis_subscription **subscribers;
 	/*! Allocated length of the subscribers array */
 	size_t num_subscribers_max;
@@ -143,9 +157,8 @@
 {
 	struct stasis_topic *topic = obj;
 
-	/* Subscribers hold a refernce to topics, so they should all be
-	 * unsubscribed before we get here.
-	 */
+	/* Subscribers hold a reference to topics, so they should all be
+	 * unsubscribed before we get here. */
 	ast_assert(topic->num_subscribers_current == 0);
 	ast_free(topic->name);
 	topic->name = NULL;
@@ -196,7 +209,7 @@
 	/*! Data pointer to be handed to the callback. */
 	void *data;
 
-	/*! Lock for joining with subscription. */
+	/*! Lock for completion flags \c final_message_{rxed,processed}. */
 	ast_mutex_t join_lock;
 	/*! Condition for joining with subscription. */
 	ast_cond_t join_cond;
@@ -329,11 +342,6 @@
 	return NULL;
 }
 
-/*!
- * \brief Block until the final message has been received on a subscription.
- *
- * \param subscription Subscription to wait on.
- */
 void stasis_subscription_join(struct stasis_subscription *subscription)
 {
 	if (subscription) {
@@ -436,7 +444,12 @@
 		topic->num_subscribers_max *= 2;
 	}
 
-	/* Don't ref sub here or we'll cause a reference cycle. */
+	/* 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. */
 	topic->subscribers[topic->num_subscribers_current++] = sub;
 	return 0;
 }
@@ -505,9 +518,8 @@
 void stasis_forward_message(struct stasis_topic *t, struct stasis_topic *publisher_topic, struct stasis_message *message)
 {
 	size_t i;
-	/* The dispatch may dispose of the final reference to the topic. Hold
-	 * it open until after the unlock.
-	 */
+	/* The topic may be unref'ed by the subscription invocation.
+	 * Make sure we hold onto a reference while dispatching. */
 	RAII_VAR(struct stasis_topic *, topic, ao2_ref1(t), ao2_cleanup);
 	SCOPED_AO2LOCK(lock, topic);
 
@@ -718,7 +730,7 @@
 	ast_log(LOG_ERROR, "Use of %s() before init/after destruction\n", name);
 }
 
-/*! \brief Cleanup function */
+/*! \brief Shutdown function */
 static void stasis_exit(void)
 {
 	ast_threadpool_shutdown(pool);




More information about the asterisk-commits mailing list