[asterisk-commits] dlee: branch dlee/stasis-core r381805 - /team/dlee/stasis-core/main/stasis.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Feb 19 16:25:11 CST 2013
Author: dlee
Date: Tue Feb 19 16:25:08 2013
New Revision: 381805
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=381805
Log:
Handle unsubscribe/dispatch race conditions
Modified:
team/dlee/stasis-core/main/stasis.c
Modified: team/dlee/stasis-core/main/stasis.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/stasis-core/main/stasis.c?view=diff&rev=381805&r1=381804&r2=381805
==============================================================================
--- team/dlee/stasis-core/main/stasis.c (original)
+++ team/dlee/stasis-core/main/stasis.c Tue Feb 19 16:25:08 2013
@@ -58,7 +58,6 @@
/* Forward declarations for the tightly-coupled subscription object */
struct stasis_subscription;
static int topic_add_subscription(struct stasis_topic *topic, struct stasis_subscription *sub);
-static int topic_remove_subscription(struct stasis_topic *topic, struct stasis_subscription *sub);
static void topic_dtor(void *obj)
{
@@ -66,7 +65,7 @@
ast_free(topic->name);
topic->name = NULL;
while (topic->num_subscribers_current > 0) {
- topic_remove_subscription(topic, topic->subscribers[0]);
+ stasis_unsubscribe(topic->subscribers[0]);
}
ast_free(topic->subscribers);
topic->subscribers = NULL;
@@ -170,10 +169,26 @@
void stasis_unsubscribe(struct stasis_subscription *sub)
{
- if (sub && sub->topic) {
- if (topic_remove_subscription(sub->topic, sub) != 0) {
- /* If our topic pointer is wrong, something is seriously messed up */
- ast_assert(0);
+ size_t i;
+
+ if (sub) {
+ SCOPED_AO2LOCK(lock, sub);
+
+ if (sub->topic) {
+ struct stasis_topic *topic = sub->topic;
+ SCOPED_AO2LOCK(lock, topic);
+
+ for (i = 0; i < topic->num_subscribers_current; ++i) {
+ if (topic->subscribers[i] == sub) {
+ sub->topic = NULL;
+ /* swap [i] with last entry; remove last entry */
+ topic->subscribers[i] = topic->subscribers[--topic->num_subscribers_current];
+ ao2_cleanup(sub);
+ return;
+ }
+ }
+
+ ast_log(LOG_ERROR, "Internal error: subscription has invalid topic\n");
}
}
}
@@ -204,31 +219,6 @@
ao2_ref(sub, +1);
topic->subscribers[topic->num_subscribers_current++] = sub;
return 0;
-}
-
-/*!
- * \brief Remove a subscriber from a topic.
- * \param topic Topic
- * \param sub Subscriber
- * \return 0 on success
- * \return Non-zero is subscriber is not subscribed to the topic.
- */
-static int topic_remove_subscription(struct stasis_topic *topic, struct stasis_subscription *sub)
-{
- size_t i;
- SCOPED_AO2LOCK(lock, topic);
-
- for (i = 0; i < topic->num_subscribers_current; ++i) {
- if (topic->subscribers[i] == sub) {
- sub->topic = NULL;
- /* swap [i] with last entry; remove last entry */
- topic->subscribers[i] = topic->subscribers[--topic->num_subscribers_current];
- ao2_cleanup(sub);
- return 0;
- }
- }
-
- return -1;
}
/*!
@@ -286,10 +276,25 @@
static int dispatch_exec(void *data)
{
RAII_VAR(struct dispatch *, dispatch, data, ao2_cleanup);
-
- ast_assert(dispatch->sub->topic != NULL);
-
- dispatch->sub->callback(dispatch->sub->data, dispatch->sub->topic, dispatch->message);
+ RAII_VAR(struct stasis_topic *, sub_topic, NULL, ao2_cleanup);
+
+ /* If the subscription's topic is NULL, then we've been unsubscribed,
+ * and don't dispatch. Check this while locking the subscription, but
+ * don't hold the lock while dispatching.
+ */
+ {
+ SCOPED_AO2LOCK(lock, dispatch->sub);
+ if (!dispatch->sub->topic) {
+ return 0;
+ }
+ sub_topic = dispatch->sub->topic;
+ ao2_ref(sub_topic, +1);
+ }
+
+ dispatch->sub->callback(dispatch->sub->data,
+ sub_topic,
+ dispatch->message);
+
return 0;
}
More information about the asterisk-commits
mailing list