]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
mpegts: add MT_DEFER tables for descrambler
authorJaroslav Kysela <perex@perex.cz>
Thu, 10 Jul 2014 18:16:46 +0000 (20:16 +0200)
committerJaroslav Kysela <perex@perex.cz>
Thu, 10 Jul 2014 18:50:43 +0000 (20:50 +0200)
This patch tries to fix mutex deadlocks:

descrambler_lock <-> input_lock

The defered table type allows to move the critical
(pid open/close) calls outside the table registration
calls.

src/descrambler/descrambler.c
src/input/mpegts.h
src/input/mpegts/mpegts_input.c
src/input/mpegts/mpegts_mux.c
src/input/mpegts/mpegts_table.c

index 030efa4b66ec0f3ca841f7b5809c1af62d185624..a3d448828f0c32b50bca7ae31638adabf42f2746 100755 (executable)
@@ -442,7 +442,8 @@ descrambler_open_pid_( mpegts_mux_t *mux, void *opaque, int pid,
     dt = calloc(1, sizeof(*dt));
     TAILQ_INIT(&dt->sections);
     dt->table = mpegts_table_add(mux, 0, 0, descrambler_table_callback,
-                                 dt, "descrambler", MT_FULL | flags, pid);
+                                 dt, "descrambler",
+                                 MT_FULL | MT_DEFER | flags, pid);
     if (dt->table)
       dt->table->mt_service = (mpegts_service_t *)service;
     TAILQ_INSERT_TAIL(&mux->mm_descrambler_tables, dt, link);
index f4674faa4d55b373720fc5b4fdeb521ce8b9cab2..61bb2ba407f996b5a9a8014ffdf5cc9c15f3bf7f 100644 (file)
@@ -142,14 +142,15 @@ struct mpegts_table
    */
   int mt_flags;
 
-#define MT_CRC      0x01
-#define MT_FULL     0x02
-#define MT_QUICKREQ 0x04
-#define MT_RECORD   0x08
-#define MT_SKIPSUBS 0x10
-#define MT_SCANSUBS 0x20
-#define MT_FAST     0x40
-#define MT_SLOW     0x80
+#define MT_CRC      0x0001
+#define MT_FULL     0x0002
+#define MT_QUICKREQ 0x0004
+#define MT_RECORD   0x0008
+#define MT_SKIPSUBS 0x0010
+#define MT_SCANSUBS 0x0020
+#define MT_FAST     0x0040
+#define MT_SLOW     0x0080
+#define MT_DEFER    0x0100
 
   /**
    * Cycle queue
@@ -164,6 +165,7 @@ struct mpegts_table
    */
 
   LIST_ENTRY(mpegts_table) mt_link;
+  LIST_ENTRY(mpegts_table) mt_defer_link;
   mpegts_mux_t *mt_mux;
 
   char *mt_name;
@@ -174,8 +176,10 @@ struct mpegts_table
   RB_HEAD(,mpegts_table_state) mt_state;
   int mt_complete;
   int mt_incomplete;
-  int mt_finished;
-  int mt_subscribed;
+  uint8_t mt_finished;
+  uint8_t mt_subscribed;
+  uint8_t mt_defer_cmd;
+  uint8_t mt_defer_reg;
 
   int mt_count;
 
@@ -371,6 +375,8 @@ struct mpegts_mux
 
   int                         mm_num_tables;
   LIST_HEAD(, mpegts_table)   mm_tables;
+  LIST_HEAD(, mpegts_table)   mm_defer_tables;
+  pthread_mutex_t             mm_defer_tables_lock;
   TAILQ_HEAD(, mpegts_table)  mm_table_queue;
 
   LIST_HEAD(, caid)           mm_descrambler_caids;
index 77f752030ae72597ef469cc3becb25b91cd45529..4ef4268fa331ce744d36a7943f1339bc1523ed02 100644 (file)
@@ -576,6 +576,51 @@ mpegts_input_table_dispatch ( mpegts_mux_t *mm, const uint8_t *tsb )
   }
 }
 
+static void
+mpegts_input_table_waiting ( mpegts_input_t *mi, mpegts_mux_t *mm )
+{
+  mpegts_table_t *mt;
+  int type;
+
+  pthread_mutex_lock(&mm->mm_defer_tables_lock);
+  while ((mt = LIST_FIRST(&mm->mm_defer_tables)) != NULL) {
+    LIST_REMOVE(mt, mt_defer_link);
+    if (mt->mt_destroyed)
+      continue;
+    type = 0;
+    if (mt->mt_flags & MT_FAST) type |= MPS_FTABLE;
+    if (mt->mt_flags & MT_SLOW) type |= MPS_TABLE;
+    if (mt->mt_flags & MT_RECORD) type |= MPS_STREAM;
+    if ((type & (MPS_FTABLE | MPS_TABLE)) == 0) type |= MPS_TABLE;
+    if (mt->mt_defer_cmd == 1) {
+      mt->mt_defer_cmd = 0;
+      mt->mt_defer_reg = 1;
+      LIST_INSERT_HEAD(&mm->mm_tables, mt, mt_link);
+      mm->mm_num_tables++;
+      if (!mt->mt_subscribed) {
+        mt->mt_subscribed = 1;
+        pthread_mutex_unlock(&mm->mm_defer_tables_lock);
+        mi->mi_open_pid(mi, mm, mt->mt_pid, type, mt);
+      }
+    } else if (mt->mt_defer_cmd == 2) {
+      mt->mt_defer_cmd = 0;
+      mt->mt_defer_reg = 0;
+      LIST_REMOVE(mt, mt_link);
+      mm->mm_num_tables--;
+      if (mt->mt_subscribed) {
+        mt->mt_subscribed = 0;
+        pthread_mutex_unlock(&mm->mm_defer_tables_lock);
+        mi->mi_close_pid(mi, mm, mt->mt_pid, type, mt);
+      }
+    } else {
+      pthread_mutex_unlock(&mm->mm_defer_tables_lock);
+    }
+    mpegts_table_release(mt);
+    pthread_mutex_lock(&mm->mm_defer_tables_lock);
+  }
+  pthread_mutex_unlock(&mm->mm_defer_tables_lock);
+}
+
 static void
 mpegts_input_process
   ( mpegts_input_t *mi, mpegts_packet_t *mpkt )
@@ -723,8 +768,10 @@ mpegts_input_thread ( void * p )
       
     /* Process */
     pthread_mutex_lock(&mi->mi_output_lock);
-    if (mp->mp_mux && mp->mp_mux->mm_active)
+    if (mp->mp_mux && mp->mp_mux->mm_active) {
+      mpegts_input_table_waiting(mi, mp->mp_mux);
       mpegts_input_process(mi, mp);
+    }
     pthread_mutex_unlock(&mi->mi_output_lock);
 
     /* Cleanup */
index 1e1fa2bf28ee15135b4087586eb97e54caa5ff6f..58094cee86f7e4d95944b99631bd1967f11f6c14 100644 (file)
@@ -720,6 +720,18 @@ mpegts_mux_open_table ( mpegts_mux_t *mm, mpegts_table_t *mt, int subscribe )
     mm->mm_num_tables++;
     return;
   }
+  if (mt->mt_flags & MT_DEFER) {
+    pthread_mutex_lock(&mm->mm_defer_tables_lock);
+    if (mt->mt_defer_reg || mt->mt_defer_cmd == 1) {
+      pthread_mutex_unlock(&mm->mm_defer_tables_lock);
+      return;
+    }
+    mpegts_table_grab(mt); /* thread will release the table */
+    mt->mt_defer_cmd = 1;
+    LIST_INSERT_HEAD(&mm->mm_defer_tables, mt, mt_defer_link);
+    pthread_mutex_unlock(&mm->mm_defer_tables_lock);
+    return;
+  }
   mi = mm->mm_active->mmi_input;
   pthread_mutex_lock(&mi->mi_output_lock);
   LIST_INSERT_HEAD(&mm->mm_tables, mt, mt_link);
@@ -747,6 +759,29 @@ mpegts_mux_close_table ( mpegts_mux_t *mm, mpegts_table_t *mt )
     mm->mm_num_tables--;
     return;
   }
+  if (mt->mt_flags & MT_DEFER) {
+    pthread_mutex_lock(&mm->mm_defer_tables_lock);
+    if (mt->mt_defer_cmd == 2) {
+      pthread_mutex_unlock(&mm->mm_defer_tables_lock);
+      return;
+    }
+    if (mt->mt_defer_cmd == 1) {
+      LIST_REMOVE(mt, mt_defer_link);
+      mt->mt_defer_cmd = 0;
+      pthread_mutex_unlock(&mm->mm_defer_tables_lock);
+      mpegts_table_release(mt);
+      return;
+    }
+    if (!mt->mt_defer_reg) {
+      pthread_mutex_unlock(&mm->mm_defer_tables_lock);
+      return;
+    }
+    mpegts_table_grab(mt); /* thread will release the table */
+    mt->mt_defer_cmd = 2;
+    LIST_INSERT_HEAD(&mm->mm_defer_tables, mt, mt_defer_link);
+    pthread_mutex_unlock(&mm->mm_defer_tables_lock);
+    return;
+  }
   mi = mm->mm_active->mmi_input;
   pthread_mutex_lock(&mi->mi_output_lock);
   LIST_REMOVE(mt, mt_link);
@@ -876,6 +911,7 @@ mpegts_mux_create0
   /* Table processing */
   mm->mm_open_table          = mpegts_mux_open_table;
   mm->mm_close_table         = mpegts_mux_close_table;
+  pthread_mutex_init(&mm->mm_defer_tables_lock, NULL);
   TAILQ_INIT(&mm->mm_table_queue);
   LIST_INIT(&mm->mm_descrambler_caids);
   TAILQ_INIT(&mm->mm_descrambler_tables);
index 6632b51e26fcdc299ed48de9cfda54a0c566f5be..5032a0de4c33cb5532daa63081f6844199cda5e7 100644 (file)
@@ -197,8 +197,18 @@ mpegts_table_flush_all ( mpegts_mux_t *mm )
 {
   mpegts_table_t        *mt;
   descrambler_flush_tables(mm);
-  while ((mt = LIST_FIRST(&mm->mm_tables)))
+  pthread_mutex_lock(&mm->mm_defer_tables_lock);
+  while ((mt = LIST_FIRST(&mm->mm_defer_tables))) {
+    LIST_REMOVE(mt, mt_defer_link);
+    mt->mt_defer_cmd = 0;
+    mpegts_table_release(mt);
+  }
+  pthread_mutex_unlock(&mm->mm_defer_tables_lock);
+  while ((mt = LIST_FIRST(&mm->mm_tables))) {
+    if ((mt->mt_flags & MT_DEFER) && mt->mt_defer_reg)
+      mt->mt_flags &= ~MT_DEFER; /* force destroy */
     mpegts_table_destroy(mt);
+  }
 }
 
 /*