]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Issue #1666 - dvb: rework the adapter tuning to stop possible deadlock
authorAdam Sutton <dev@adamsutton.me.uk>
Fri, 22 Mar 2013 12:12:29 +0000 (12:12 +0000)
committerAdam Sutton <dev@adamsutton.me.uk>
Tue, 26 Mar 2013 10:04:26 +0000 (10:04 +0000)
(cherry picked from commit 75856cd5a6ae53cd7103140d06dfd0b2f77ff55f)

src/dvb/dvb.h
src/dvb/dvb_adapter.c
src/dvb/dvb_fe.c

index 335ac3c05e8874bc3fa8576b52d9e58760868e09..3b3e8f1fc8caba7471689edfa3278226eda9934d 100644 (file)
@@ -209,6 +209,7 @@ typedef struct th_dvb_adapter {
   uint32_t tda_enabled;
 
   int tda_locked;
+  time_t tda_monitor;
 
   const char *tda_rootpath;
   char *tda_identifier;
@@ -250,7 +251,6 @@ typedef struct th_dvb_adapter {
   struct service_list tda_transports; /* Currently bound transports */
 
   gtimer_t tda_fe_monitor_timer;
-  int tda_fe_monitor_hold;
 
   int tda_sat; // Set if this adapter is a satellite receiver (DVB-S, etc) 
 
index 02b3fb8b47f48c77ee8636a8377c14e140e796e3..79b6ea0ad9c220fd26d0b1ddc574d30979a9853f 100644 (file)
@@ -1020,13 +1020,25 @@ static void *
 dvb_adapter_input_dvr(void *aux)
 {
   th_dvb_adapter_t *tda = aux;
-  th_dvb_mux_instance_t *tdmi;
   int fd = -1, i, r, c, efd, nfds, dmx = -1;
   uint8_t tsb[188 * 10];
   service_t *t;
   struct epoll_event ev;
-  int delay = 10, locked = 0;
-  fe_status_t festat;
+  int delay = 10;
+
+  /* Install RAW demux */
+  if (tda->tda_rawmode) {
+    if ((dmx = dvb_adapter_raw_filter(tda)) == -1) {
+      tvhlog(LOG_ALERT, "dvb", "Unable to install raw mux filter");
+      return NULL;
+    }
+  }
+
+  /* Open DVR */
+  if ((fd = tvh_open(tda->tda_dvr_path, O_RDONLY | O_NONBLOCK, 0)) == -1) {
+    close(dmx);
+    return NULL;
+  }
 
   /* Create poll */
   efd = epoll_create(2);
@@ -1034,6 +1046,8 @@ dvb_adapter_input_dvr(void *aux)
   ev.events  = EPOLLIN;
   ev.data.fd = tda->tda_dvr_pipe.rd;
   epoll_ctl(efd, EPOLL_CTL_ADD, tda->tda_dvr_pipe.rd, &ev);
+  ev.data.fd = fd;
+  epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);
 
   r = i = 0;
   while(1) {
@@ -1041,62 +1055,12 @@ dvb_adapter_input_dvr(void *aux)
     /* Wait for input */
     nfds = epoll_wait(efd, &ev, 1, delay);
 
-    /* Exit */
-    if ((nfds > 0) && (ev.data.fd != fd)) break;
-
-    /* Check for lock */
-    if (!locked) {
-      if (ioctl(tda->tda_fe_fd, FE_READ_STATUS, &festat))
-        continue;
-      if (!(festat & FE_HAS_LOCK))
-        continue;
-
-      /* Open DVR */
-      fd = tvh_open(tda->tda_dvr_path, O_RDONLY | O_NONBLOCK, 0);
-      if (fd == -1) {
-        tvhlog(LOG_ALERT, "dvb", "Unable to open %s -- %s",
-               tda->tda_dvr_path, strerror(errno));
-        break;
-      }
-      ev.data.fd = fd;
-      epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);
-
-      /* Note: table handlers must be installed with global lock */
-      pthread_mutex_lock(&global_lock);
-      tda->tda_locked = locked = 1;
-      delay           = -1;
-      if ((tdmi = tda->tda_mux_current)) {
-
-        /* Install table handlers */
-        dvb_table_add_default(tdmi);
-        epggrab_mux_start(tdmi);
-
-        /* Raw filter */
-        if(tda->tda_rawmode)
-          dmx = dvb_adapter_raw_filter(tda);
-
-        /* Service filters */
-        pthread_mutex_lock(&tda->tda_delivery_mutex);
-        LIST_FOREACH(t, &tda->tda_transports, s_active_link) {
-          if (t->s_dvb_mux_instance == tdmi) {
-            tda->tda_open_service(tda, t);
-            dvb_table_add_pmt(tdmi, t->s_pmt_pid);
-          }
-        }
-        pthread_mutex_unlock(&tda->tda_delivery_mutex);
-      }
-      pthread_mutex_unlock(&global_lock);
-
-      /* Error */
-      if (tda->tda_rawmode && (dmx == -1)) {
-        tvhlog(LOG_ALERT, "dvb", "Unable to install raw mux filter");
-        break;
-      }
-    }
-
     /* No data */
     if (nfds < 1) continue;
 
+    /* Exit */
+    if (ev.data.fd != fd) break;
+
     /* Read data */
     c = read(fd, tsb+r, sizeof(tsb)-r);
     if (c < 0) {
index d0924c691ea36dc5667a3d5676d9a31fa412205b..4b33995259d67b0d09a4bee7e37f812fa1c0493d 100644 (file)
@@ -101,8 +101,6 @@ dvb_fe_monitor(void *aux)
   int store = 0;
   int notify = 0;
 
-  gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1);
-
   if(tdmi == NULL)
     return;
 
@@ -110,9 +108,8 @@ dvb_fe_monitor(void *aux)
    * Read out front end status
    */
   if(ioctl(tda->tda_fe_fd, FE_READ_STATUS, &fe_status))
-    fe_status = 0;
-
-  if(fe_status & FE_HAS_LOCK)
+    status = TDMI_FE_UNKNOWN;
+  else if(fe_status & FE_HAS_LOCK)
     status = -1;
   else if(fe_status & (FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_CARRIER))
     status = TDMI_FE_BAD_SIGNAL;
@@ -121,18 +118,34 @@ dvb_fe_monitor(void *aux)
   else
     status = TDMI_FE_NO_SIGNAL;
 
-  if(tda->tda_fe_monitor_hold > 0) {
-    /* Post tuning threshold */
-    if(status == -1) { /* We have a lock, don't hold off */
-      tda->tda_fe_monitor_hold = 0; 
-      /* Reset FEC counter */
-      dvb_fe_get_unc(tda);
+  /**
+   * Waiting for initial lock
+   */
+  if(tda->tda_locked == 0) {
+
+    /* Read */
+    if (status == -1) {
+      tda->tda_locked = 1;
+      dvb_adapter_start(tda, TDA_OPT_ALL);
+      gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1);
+
+    /* Re-arm (50ms) */
     } else {
-      tda->tda_fe_monitor_hold--;
-      return;
+      gtimer_arm_ms(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 50);
+
+      /* Monitor (1 per sec) */
+      if (dispatch_clock < tda->tda_monitor)  
+        return;
+      tda->tda_monitor = dispatch_clock + 1;
     }
+
+  } else {
+    gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1);
   }
 
+  /*
+   * Update stats 
+   */
   if(status == -1) {
     /* Read FEC counter (delta) */
 
@@ -312,46 +325,6 @@ dvb_fe_stop(th_dvb_mux_instance_t *tdmi, int retune)
 
 #if DVB_API_VERSION >= 5
 
-static int check_frontend (int fe_fd, int dvr, int human_readable) {
-  (void)dvr;
-  fe_status_t status;
-  uint16_t snr, signal;
-  uint32_t ber;
-  int timeout = 0;
-
-  do {
-    if (ioctl(fe_fd, FE_READ_STATUS, &status) == -1)
-      perror("FE_READ_STATUS failed");
-    /* some frontends might not support all these ioctls, thus we
-     * avoid printing errors
-     */
-    if (ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal) == -1)
-      signal = -2;
-    if (ioctl(fe_fd, FE_READ_SNR, &snr) == -1)
-      snr = -2;
-    if (ioctl(fe_fd, FE_READ_BER, &ber) == -1)
-      ber = -2;
-
-    if (human_readable) {
-      printf ("status %02x | signal %3u%% | snr %3u%% | ber %d | ",
-          status, (signal * 100) / 0xffff, (snr * 100) / 0xffff, ber);
-    } else {
-      printf ("status %02x | signal %04x | snr %04x | ber %08x | ",
-          status, signal, snr, ber);
-    }
-    if (status & FE_HAS_LOCK)
-      printf("FE_HAS_LOCK");
-    printf("\n");
-
-    if ((status & FE_HAS_LOCK) || (++timeout >= 10))
-      break;
-
-    usleep(1000000);
-  } while (1);
-
-  return 0;
-}
-
 static struct dtv_property clear_p[] = {
   { .cmd = DTV_CLEAR },
 };
@@ -361,7 +334,6 @@ static struct dtv_properties clear_cmdseq = {
   .props = clear_p
 };
 
-
 /**
  *
  */
@@ -404,8 +376,6 @@ dvb_fe_tune_s2(th_dvb_mux_instance_t *tdmi, dvb_mux_conf_t *dmc)
   /* do tuning now */
   r = ioctl(tda->tda_fe_fd, FE_SET_PROPERTY, &_dvbs_cmdseq);
 
-  if(0)
-    check_frontend (tda->tda_fe_fd, 0, 1);
   return r;
 
 }
@@ -493,8 +463,6 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
 
   dvb_mux_nicename(buf, sizeof(buf), tdmi);
 
-  tda->tda_fe_monitor_hold = 4;
-
 #if DVB_API_VERSION >= 5
   if (tda->tda_type == FE_QPSK) {
     tvhlog(LOG_DEBUG, "dvb", "\"%s\" tuning via s2api to \"%s\" (%d, %d Baud, "
@@ -524,19 +492,16 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
     /* Mark as bad */
     if (errno == EINVAL)
       dvb_mux_set_enable(tdmi, 0);
+
+    dvb_adapter_stop(tda, TDA_OPT_ALL);
     return SM_CODE_TUNING_FAILED;
   }
 
   tda->tda_mux_current = tdmi;
 
-  dvb_adapter_start(tda, TDA_OPT_ALL);
-
-  gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1);
-
-#if 0
-  dvb_table_add_default(tdmi);
-  epggrab_mux_start(tdmi);
-#endif
+  time(&tda->tda_monitor);
+  tda->tda_monitor += 4; // wait a few secs before monitoring (unlocked)
+  gtimer_arm_ms(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 50);
 
   dvb_adapter_notify(tda);
   return 0;