Close all DVB device file descriptors when not in use. Fixes #892.

This commit is contained in:
Adam Sutton 2012-08-22 15:19:17 +01:00
parent b5cfa01789
commit f88892bd67
4 changed files with 100 additions and 27 deletions

View file

@ -21,6 +21,7 @@
#include <linux/dvb/version.h>
#include <linux/dvb/frontend.h>
#include <pthread.h>
#include "htsmsg.h"
@ -184,6 +185,7 @@ typedef struct th_dvb_adapter {
uint32_t tda_disable_pmt_monitor;
char *tda_displayname;
char *tda_fe_path;
int tda_fe_fd;
int tda_type;
struct dvb_frontend_info *tda_fe_info;
@ -192,7 +194,9 @@ typedef struct th_dvb_adapter {
char *tda_demux_path;
char *tda_dvr_path;
char *tda_dvr_path;
pthread_t tda_dvr_thread;
int tda_dvr_pipe[2];
int tda_hostconnection;
@ -279,6 +283,10 @@ void dvb_adapter_init(uint32_t adapter_mask);
void dvb_adapter_mux_scanner(void *aux);
void dvb_adapter_start (th_dvb_adapter_t *tda);
void dvb_adapter_stop (th_dvb_adapter_t *tda);
void dvb_adapter_set_displayname(th_dvb_adapter_t *tda, const char *s);
void dvb_adapter_set_auto_discovery(th_dvb_adapter_t *tda, int on);
@ -404,7 +412,7 @@ htsmsg_t *dvb_transport_build_msg(struct service *t);
*/
int dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason);
void dvb_fe_stop(th_dvb_mux_instance_t *tdmi);
void dvb_fe_stop(th_dvb_mux_instance_t *tdmi, int retune);
/**

View file

@ -16,12 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#include <pthread.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
@ -368,12 +370,10 @@ dvb_adapter_checkspeed(th_dvb_adapter_t *tda)
static void
tda_add(int adapter_num)
{
char path[200];
char fname[256];
char path[200], fname[256];
int fe, i, r;
th_dvb_adapter_t *tda;
char buf[400];
pthread_t ptid;
snprintf(path, sizeof(path), "/dev/dvb/adapter%d", adapter_num);
snprintf(fname, sizeof(fname), "%s/frontend0", path);
@ -394,18 +394,20 @@ tda_add(int adapter_num)
snprintf(tda->tda_demux_path, 256, "%s/demux0", path);
tda->tda_dvr_path = malloc(256);
snprintf(tda->tda_dvr_path, 256, "%s/dvr0", path);
tda->tda_fe_path = strdup(fname);
tda->tda_fe_fd = fe;
tda->tda_fe_fd = -1;
tda->tda_dvr_pipe[0] = -1;
tda->tda_fe_info = malloc(sizeof(struct dvb_frontend_info));
if(ioctl(tda->tda_fe_fd, FE_GET_INFO, tda->tda_fe_info)) {
if(ioctl(fe, FE_GET_INFO, tda->tda_fe_info)) {
tvhlog(LOG_ALERT, "dvb", "%s: Unable to query adapter", fname);
close(fe);
free(tda);
return;
}
close(fe);
tda->tda_type = tda->tda_fe_info->type;
@ -437,7 +439,6 @@ tda_add(int adapter_num)
TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link);
pthread_create(&ptid, NULL, dvb_adapter_input_dvr, tda);
dvb_table_init(tda);
@ -447,6 +448,48 @@ tda_add(int adapter_num)
gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 1);
}
void
dvb_adapter_start ( th_dvb_adapter_t *tda )
{
/* Open front end */
if (tda->tda_fe_fd == -1) {
tda->tda_fe_fd = tvh_open(tda->tda_fe_path, O_RDWR | O_NONBLOCK, 0);
if (tda->tda_fe_fd == -1) return;
tvhlog(LOG_DEBUG, "dvb", "%s opened frontend %s", tda->tda_rootpath, tda->tda_fe_path);
}
/* Start DVR thread */
if (tda->tda_dvr_pipe[0] == -1) {
assert(pipe2(tda->tda_dvr_pipe, O_NONBLOCK | O_CLOEXEC) != -1);
pthread_create(&tda->tda_dvr_thread, NULL, dvb_adapter_input_dvr, tda);
tvhlog(LOG_DEBUG, "dvb", "%s started dvr thread", tda->tda_rootpath);
}
}
void
dvb_adapter_stop ( th_dvb_adapter_t *tda )
{
/* Poweroff */
dvb_adapter_poweroff(tda);
/* Close front end */
if (tda->tda_fe_fd != -1) {
tvhlog(LOG_DEBUG, "dvb", "%s closing frontend", tda->tda_rootpath);
close(tda->tda_fe_fd);
tda->tda_fe_fd = -1;
}
/* Stop DVR thread */
if (tda->tda_dvr_pipe[0] != -1) {
tvhlog(LOG_DEBUG, "dvb", "%s stopping thread", tda->tda_rootpath);
assert(write(tda->tda_dvr_pipe[1], "", 1) == 1);
pthread_join(tda->tda_dvr_thread, NULL);
close(tda->tda_dvr_pipe[0]);
close(tda->tda_dvr_pipe[1]);
tda->tda_dvr_pipe[0] = -1;
tvhlog(LOG_DEBUG, "dvb", "%s stopped thread", tda->tda_rootpath);
}
}
/**
*
@ -581,8 +624,7 @@ dvb_adapter_mux_scanner(void *aux)
/* Ensure we stop current mux and power off (if required) */
if (tda->tda_mux_current)
dvb_fe_stop(tda->tda_mux_current);
dvb_adapter_poweroff(tda);
dvb_fe_stop(tda->tda_mux_current, 0);
}
/**
@ -659,41 +701,58 @@ static void *
dvb_adapter_input_dvr(void *aux)
{
th_dvb_adapter_t *tda = aux;
int fd, i, r;
int fd, i, r, efd, nfds;
uint8_t tsb[188 * 10];
service_t *t;
struct epoll_event ev;
fd = tvh_open(tda->tda_dvr_path, O_RDONLY, 0);
fd = tvh_open(tda->tda_dvr_path, O_RDONLY | O_NONBLOCK, 0);
if(fd == -1) {
tvhlog(LOG_ALERT, "dvb", "%s: unable to open dvr", tda->tda_dvr_path);
return NULL;
}
/* Create poll */
efd = epoll_create(2);
ev.events = EPOLLIN;
ev.data.fd = fd;
epoll_ctl(efd, EPOLL_CTL_ADD, fd, &ev);
ev.data.fd = tda->tda_dvr_pipe[0];
epoll_ctl(efd, EPOLL_CTL_ADD, tda->tda_dvr_pipe[0], &ev);
while(1){
/* Wait for input */
nfds = epoll_wait(efd, &ev, 1, -1);
if (nfds < 1) continue;
if (ev.data.fd != fd) break;
while(1) {
r = read(fd, tsb, sizeof(tsb));
pthread_mutex_lock(&tda->tda_delivery_mutex);
for(i = 0; i < r; i += 188) {
LIST_FOREACH(t, &tda->tda_transports, s_active_link)
if(t->s_dvb_mux_instance == tda->tda_mux_current)
ts_recv_packet1(t, tsb + i, NULL);
if(t->s_dvb_mux_instance == tda->tda_mux_current)
ts_recv_packet1(t, tsb + i, NULL);
}
if(tda->tda_dump_fd != -1) {
if(write(tda->tda_dump_fd, tsb, r) != r) {
tvhlog(LOG_ERR, "dvb",
tvhlog(LOG_ERR, "dvb",
"\"%s\" unable to write to mux dump file -- %s",
tda->tda_identifier, strerror(errno));
close(tda->tda_dump_fd);
tda->tda_dump_fd = -1;
}
close(tda->tda_dump_fd);
tda->tda_dump_fd = -1;
}
}
pthread_mutex_unlock(&tda->tda_delivery_mutex);
}
close(efd);
close(fd);
return NULL;
}

View file

@ -201,7 +201,7 @@ dvb_fe_monitor(void *aux)
* Stop the given TDMI
*/
void
dvb_fe_stop(th_dvb_mux_instance_t *tdmi)
dvb_fe_stop(th_dvb_mux_instance_t *tdmi, int retune)
{
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
@ -233,8 +233,13 @@ dvb_fe_stop(th_dvb_mux_instance_t *tdmi)
}
epggrab_mux_stop(tdmi, 0);
time(&tdmi->tdmi_lost_adapter);
if (!retune) {
gtimer_disarm(&tda->tda_fe_monitor_timer);
dvb_adapter_stop(tda);
}
}
@ -439,9 +444,10 @@ dvb_fe_tune(th_dvb_mux_instance_t *tdmi, const char *reason)
}
if(tda->tda_mux_current != NULL)
dvb_fe_stop(tda->tda_mux_current);
dvb_fe_stop(tda->tda_mux_current, 1);
else
dvb_adapter_start(tda);
if(tda->tda_type == FE_QPSK) {
/* DVB-S */

View file

@ -317,7 +317,7 @@ dvb_mux_destroy(th_dvb_mux_instance_t *tdmi)
dvb_transport_notify_by_adapter(tda);
if(tda->tda_mux_current == tdmi)
dvb_fe_stop(tda->tda_mux_current);
dvb_fe_stop(tda->tda_mux_current, 0);
if(tdmi->tdmi_conf.dmc_satconf != NULL)
LIST_REMOVE(tdmi, tdmi_satconf_link);