]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
subscription: fix another unsubscribe / unlink crashes
authorJaroslav Kysela <perex@perex.cz>
Sat, 7 Nov 2015 19:20:41 +0000 (20:20 +0100)
committerJaroslav Kysela <perex@perex.cz>
Sat, 7 Nov 2015 19:20:41 +0000 (20:20 +0100)
A global timer (callback) is used in subscription_unlink_service now.
It eliminates the unlink/unsubscribe deadlocks because the timer
is released when the subscription is destroyed.

src/subscriptions.c
src/subscriptions.h

index c7b6ddb85bd6983f4f33fb2f757994c8ee38d8f1..73861ac133165414b599c86f6f80e3b9b0661739 100644 (file)
@@ -48,6 +48,11 @@ struct th_subscription_list subscriptions_remove;
 static gtimer_t             subscription_reschedule_timer;
 static int                  subscription_postpone;
 
+/**
+ *
+ */
+static void subscription_unsubscribe_cb(void *aux);
+
 /**
  *
  */
@@ -120,7 +125,7 @@ static int
 subscription_unlink_service0(th_subscription_t *s, int reason, int stop)
 {
   streaming_message_t *sm;
-  service_t *t = s->ths_service, *tr = s->ths_raw_service;
+  service_t *t = s->ths_service;
 
   /* Ignore - not actually linked */
   if (!s->ths_current_instance) goto stop;
@@ -139,15 +144,9 @@ subscription_unlink_service0(th_subscription_t *s, int reason, int stop)
   pthread_mutex_unlock(&t->s_stream_mutex);
 
   LIST_REMOVE(s, ths_service_link);
-  s->ths_service = NULL;
-  s->ths_raw_service = NULL;
 
-  if (stop && (s->ths_flags & SUBSCRIPTION_ONESHOT) != 0) {
-    if (tr)
-      LIST_REMOVE(s, ths_mux_link);
-    subscription_unsubscribe(s, 0);
-    service_remove_raw(tr);
-  }
+  if (stop && s-(s->ths_flags & SUBSCRIPTION_ONESHOT) != 0)
+    gtimer_arm(&s->ths_remove_timer, subscription_unsubscribe_cb, s, 0);
 
 stop:
   if(LIST_FIRST(&t->s_subscriptions) == NULL)
@@ -552,6 +551,12 @@ subscription_input(void *opauqe, streaming_message_t *sm)
 /**
  * Delete
  */
+static void
+subscription_unsubscribe_cb(void *aux)
+{
+  subscription_unsubscribe((th_subscription_t *)aux, 0);
+}
+
 void
 subscription_unsubscribe(th_subscription_t *s, int quiet)
 {
@@ -563,11 +568,12 @@ subscription_unsubscribe(th_subscription_t *s, int quiet)
   if (s == NULL)
     return;
 
-  t = s->ths_service;
-  raw = s->ths_raw_service;
-
   lock_assert(&global_lock);
 
+  t   = s->ths_service;
+  raw = s->ths_raw_service;
+
+  assert(s->ths_state != SUBSCRIPTION_ZOMBIE);
   s->ths_state = SUBSCRIPTION_ZOMBIE;
 
   service_instance_list_clear(&s->ths_instances);
@@ -576,8 +582,10 @@ subscription_unsubscribe(th_subscription_t *s, int quiet)
   LIST_SAFE_REMOVE(s, ths_remove_link);
 
 #if ENABLE_MPEGTS
-  if (raw)
+  if (raw && t == raw) {
     LIST_REMOVE(s, ths_mux_link);
+    service_remove_raw(raw);
+  }
 #endif
 
   if (s->ths_channel != NULL) {
@@ -596,23 +604,16 @@ subscription_unsubscribe(th_subscription_t *s, int quiet)
     tvh_strlcatf(buf, sizeof(buf), l, ", client=\"%s\"", s->ths_client);
   tvhlog(quiet ? LOG_TRACE : LOG_INFO, "subscription", "%04X: %s", shortid(s), buf);
 
-  if (t) {
-    s->ths_flags &= ~SUBSCRIPTION_ONESHOT;
+  if (t)
     service_remove_subscriber(t, s, SM_CODE_OK);
-  }
 
-#if ENABLE_MPEGTS
-  if (raw && t == raw) {
-    LIST_REMOVE(s, ths_mux_link);
-    service_remove_raw(raw);
-  }
-#endif
+  gtimer_disarm(&s->ths_remove_timer);
 
   streaming_msg_free(s->ths_start_message);
 
   if(s->ths_output->st_cb == subscription_input_null)
    free(s->ths_output);
+
   free(s->ths_title);
   free(s->ths_hostname);
   free(s->ths_username);
index 270c34005fea0cb78c72bd0bcbe5bf4e6ef5d1ec..1d8311ceb1d7ece40b258888699fb4b6420af546 100644 (file)
@@ -74,6 +74,8 @@ typedef struct th_subscription {
 
   int ths_testing_error;
 
+  gtimer_t ths_remove_timer;
+
   LIST_ENTRY(th_subscription) ths_channel_link;
   struct channel *ths_channel;          /* May be NULL if channel has been
                                           destroyed during the