]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
mpegts mux: protect mux free using refcouting
authorJaroslav Kysela <perex@perex.cz>
Fri, 1 Jul 2016 08:50:00 +0000 (10:50 +0200)
committerJaroslav Kysela <perex@perex.cz>
Fri, 1 Jul 2016 08:50:00 +0000 (10:50 +0200)
src/input/mpegts.h
src/input/mpegts/iptv/iptv_mux.c
src/input/mpegts/mpegts_input.c
src/input/mpegts/mpegts_mux.c

index a12bafc279a813ea58363438a4e7d53569dc050a..7f512e97e5072e22ffb4a885dccb4488bfc5d4be 100644 (file)
@@ -419,6 +419,7 @@ typedef struct tsdebug_packet {
 struct mpegts_mux
 {
   idnode_t mm_id;
+  int      mm_refcount;
 
   /*
    * Identification
@@ -506,6 +507,7 @@ struct mpegts_mux
    */
 
   void (*mm_delete)           (mpegts_mux_t *mm, int delconf);
+  void (*mm_free)             (mpegts_mux_t *mm);
   htsmsg_t *(*mm_config_save) (mpegts_mux_t *mm, char *filename, size_t fsize);
   void (*mm_display_name)     (mpegts_mux_t*, char *buf, size_t len);
   int  (*mm_is_enabled)       (mpegts_mux_t *mm);
@@ -877,6 +879,25 @@ static inline mpegts_mux_t *mpegts_mux_find(const char *uuid)
 
 void mpegts_mux_delete ( mpegts_mux_t *mm, int delconf );
 
+void mpegts_mux_free ( mpegts_mux_t *mm );
+
+static inline void mpegts_mux_grab ( mpegts_mux_t *mm )
+{
+  int v = atomic_add(&mm->mm_refcount, 1);
+  assert(v > 0);
+}
+
+static inline int mpegts_mux_release ( mpegts_mux_t *mm )
+{
+  int v = atomic_dec(&mm->mm_refcount, 1);
+  assert(v > 0);
+  if (v == 1) {
+    mm->mm_free(mm);
+    return 1;
+  }
+  return 0;
+}
+
 void mpegts_mux_save ( mpegts_mux_t *mm, htsmsg_t *c );
 
 void mpegts_mux_tuning_error( const char *mux_uuid, mpegts_mux_instance_t *mmi_match );
index 984628e46c6754eedc778f5f97e04e3e8971dbc5..91335ad62550a7fba346c1cb86f16b4fca9dc20a 100644 (file)
@@ -274,6 +274,24 @@ iptv_mux_config_save ( mpegts_mux_t *mm, char *filename, size_t fsize )
   return c;
 }
 
+static void
+iptv_mux_free ( mpegts_mux_t *mm )
+{
+  iptv_mux_t *im = (iptv_mux_t *)mm;
+  free(im->mm_iptv_url);
+  free(im->mm_iptv_url_sane);
+  free(im->mm_iptv_url_raw);
+  free(im->mm_iptv_muxname);
+  free(im->mm_iptv_interface);
+  free(im->mm_iptv_svcname);
+  free(im->mm_iptv_env);
+  free(im->mm_iptv_hdr);
+  free(im->mm_iptv_tags);
+  free(im->mm_iptv_icon);
+  free(im->mm_iptv_epgid);
+  mpegts_mux_free(mm);
+}
+
 static void
 iptv_mux_delete ( mpegts_mux_t *mm, int delconf )
 {
@@ -286,19 +304,7 @@ iptv_mux_delete ( mpegts_mux_t *mm, int delconf )
                         idnode_uuid_as_str(&mm->mm_network->mn_id, ubuf1),
                         idnode_uuid_as_str(&mm->mm_id, ubuf2));
 
-  copy = *im; /* keep pointers */
   mpegts_mux_delete(mm, delconf);
-  free(copy.mm_iptv_url);
-  free(copy.mm_iptv_url_sane);
-  free(copy.mm_iptv_url_raw);
-  free(copy.mm_iptv_muxname);
-  free(copy.mm_iptv_interface);
-  free(copy.mm_iptv_svcname);
-  free(copy.mm_iptv_env);
-  free(copy.mm_iptv_hdr);
-  free(copy.mm_iptv_tags);
-  free(copy.mm_iptv_icon);
-  free(copy.mm_iptv_epgid);
 }
 
 static void
@@ -336,6 +342,7 @@ iptv_mux_create0 ( iptv_network_t *in, const char *uuid, htsmsg_t *conf )
   im->mm_display_name     = iptv_mux_display_name;
   im->mm_config_save      = iptv_mux_config_save;
   im->mm_delete           = iptv_mux_delete;
+  im->mm_free             = iptv_mux_free;
 
   if (!im->mm_iptv_kill_timeout)
     im->mm_iptv_kill_timeout = 5;
index a9d599a9b15449f41d5fb7f1a2b0b595a6778c7a..854b200a1e6ee85c784b324e56b0e623f2af933b 100644 (file)
@@ -1127,6 +1127,7 @@ retry:
       if (mi->mi_input_queue_size < 50*1024*1024) {
         mi->mi_input_queue_size += len2;
         memoryinfo_alloc(&mpegts_input_queue_memoryinfo, sizeof(mpegts_packet_t) + len2);
+        mpegts_mux_grab(mp->mp_mux);
         TAILQ_INSERT_TAIL(&mi->mi_input_queue, mp, mp_link);
         tvh_cond_signal(&mi->mi_input_cond, 0);
       } else {
@@ -1513,6 +1514,8 @@ mpegts_input_thread ( void * p )
     }
 
     /* Cleanup */
+    if (mp->mp_mux)
+      mpegts_mux_release(mp->mp_mux);
     free(mp);
 
 #if ENABLE_TSDEBUG
@@ -1531,6 +1534,8 @@ mpegts_input_thread ( void * p )
   while ((mp = TAILQ_FIRST(&mi->mi_input_queue))) {
     memoryinfo_free(&mpegts_input_queue_memoryinfo, sizeof(mpegts_packet_t) + mp->mp_len);
     TAILQ_REMOVE(&mi->mi_input_queue, mp, mp_link);
+    if (mp->mp_mux)
+      mpegts_mux_release(mp->mp_mux);
     free(mp);
   }
   mi->mi_input_queue_size = 0;
@@ -1606,8 +1611,10 @@ mpegts_input_flush_mux
   /* Flush input Q */
   pthread_mutex_lock(&mi->mi_input_lock);
   TAILQ_FOREACH(mp, &mi->mi_input_queue, mp_link) {
-    if (mp->mp_mux == mm)
+    if (mp->mp_mux == mm) {
+      mpegts_mux_release(mm);
       mp->mp_mux = NULL;
+    }
   }
   pthread_mutex_unlock(&mi->mi_input_lock);
 
index 1b72710dd67e398239de94ce9c3eda712df13d48..b155c77e9b786c6ea39be3a89989a8659aa389d2 100644 (file)
@@ -721,6 +721,15 @@ mpegts_mux_do_stop ( mpegts_mux_t *mm, int delconf )
   mtimer_disarm(&mm->mm_update_pids_timer);
 }
 
+void
+mpegts_mux_free ( mpegts_mux_t *mm )
+{
+  free(mm->mm_provider_network_name);
+  free(mm->mm_crid_authority);
+  free(mm->mm_charset);
+  free(mm);
+}
+
 void
 mpegts_mux_delete ( mpegts_mux_t *mm, int delconf )
 {
@@ -743,10 +752,7 @@ mpegts_mux_delete ( mpegts_mux_t *mm, int delconf )
   /* Free memory */
   idnode_save_check(&mm->mm_id, 1);
   idnode_unlink(&mm->mm_id);
-  free(mm->mm_provider_network_name);
-  free(mm->mm_crid_authority);
-  free(mm->mm_charset);
-  free(mm);
+  mpegts_mux_release(mm);
 }
 
 static htsmsg_t *
@@ -1168,6 +1174,8 @@ mpegts_mux_create0
     return NULL;
   }
 
+  mm->mm_refcount            = 1;
+
   /* Enabled by default */
   mm->mm_enabled             = MM_ENABLE;
   mm->mm_epg                 = MM_EPG_ENABLE;
@@ -1182,6 +1190,7 @@ mpegts_mux_create0
 
   /* Debug/Config */
   mm->mm_delete              = mpegts_mux_delete;
+  mm->mm_free                = mpegts_mux_free;
   mm->mm_display_name        = mpegts_mux_display_name;
   mm->mm_config_save         = mpegts_mux_config_save;
   mm->mm_is_enabled          = mpegts_mux_is_enabled;