From d75b99a610f4cab4c703f2f2dda5f84141524202 Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Fri, 22 Mar 2013 12:12:29 +0000 Subject: [PATCH] Fix #1666 - dvb: rework the adapter tuning to stop possible deadlock --- src/dvb/dvb.h | 2 +- src/dvb/dvb_adapter.c | 76 +++++++++------------------------ src/dvb/dvb_fe.c | 97 ++++++++++++++----------------------------- 3 files changed, 52 insertions(+), 123 deletions(-) diff --git a/src/dvb/dvb.h b/src/dvb/dvb.h index 335ac3c0..3b3e8f1f 100644 --- a/src/dvb/dvb.h +++ b/src/dvb/dvb.h @@ -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) diff --git a/src/dvb/dvb_adapter.c b/src/dvb/dvb_adapter.c index 02b3fb8b..79b6ea0a 100644 --- a/src/dvb/dvb_adapter.c +++ b/src/dvb/dvb_adapter.c @@ -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) { diff --git a/src/dvb/dvb_fe.c b/src/dvb/dvb_fe.c index d0924c69..4b339952 100644 --- a/src/dvb/dvb_fe.c +++ b/src/dvb/dvb_fe.c @@ -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;