Merge remote-tracking branch 'upstream/master' after all FreeBSD
related changes have been merged from upstream.
This commit is contained in:
commit
7082d8da77
12 changed files with 942 additions and 617 deletions
14
README
14
README
|
@ -1,7 +1,14 @@
|
|||
Tvheadend (TV streaming server) v3.5
|
||||
Tvheadend v3.5
|
||||
====================================
|
||||
(c) 2006 - 2013 Andreas Öman, et al.
|
||||
|
||||
|
||||
What it is
|
||||
----------
|
||||
|
||||
Tvheadend is a TV streaming server and digital video recorder, supporting DVB-S, DVB-S2, DVB-C, DVB-T, DVB-T2, ATSC, IPTV, and Analog video (V4L) as input sources.
|
||||
|
||||
|
||||
How to build for Linux
|
||||
----------------------
|
||||
|
||||
|
@ -16,7 +23,7 @@ Build the binary:
|
|||
|
||||
$ make
|
||||
|
||||
After build, the binary resides in `build.linux/`.
|
||||
After build, the binary resides in `build.linux` directory.
|
||||
|
||||
Thus, to start it, just type:
|
||||
|
||||
|
@ -24,10 +31,11 @@ Thus, to start it, just type:
|
|||
|
||||
Settings are stored in `$HOME/.hts/tvheadend`.
|
||||
|
||||
|
||||
Further information
|
||||
-------------------
|
||||
|
||||
For more information about building, including generating packages please visit:
|
||||
For more information about building, including generating packages, please visit:
|
||||
> https://tvheadend.org/projects/tvheadend/wiki/Building
|
||||
> https://tvheadend.org/projects/tvheadend/wiki/Packaging
|
||||
> https://tvheadend.org/projects/tvheadend/wiki/Git
|
||||
|
|
18
README.md
18
README.md
|
@ -1,7 +1,14 @@
|
|||
Tvheadend (TV streaming server)
|
||||
Tvheadend
|
||||
====================================
|
||||
(c) 2006 - 2013 Andreas Öman, et al.
|
||||
|
||||
|
||||
What it is
|
||||
----------
|
||||
|
||||
Tvheadend is a TV streaming server and digital video recorder, supporting DVB-S, DVB-S2, DVB-C, DVB-T, DVB-T2, ATSC, IPTV, and Analog video (V4L) as input sources.
|
||||
|
||||
|
||||
How to build for Linux
|
||||
----------------------
|
||||
|
||||
|
@ -16,7 +23,7 @@ Build the binary:
|
|||
|
||||
$ make
|
||||
|
||||
After build, the binary resides in `build.linux/`.
|
||||
After build, the binary resides in `build.linux` directory.
|
||||
|
||||
Thus, to start it, just type:
|
||||
|
||||
|
@ -24,10 +31,11 @@ Thus, to start it, just type:
|
|||
|
||||
Settings are stored in `$HOME/.hts/tvheadend`.
|
||||
|
||||
|
||||
Further information
|
||||
-------------------
|
||||
|
||||
For more information about building, including generating packages please visit:
|
||||
> https://tvheadend.org/projects/tvheadend/wiki/Building
|
||||
> https://tvheadend.org/projects/tvheadend/wiki/Packaging
|
||||
For more information about building, including generating packages, please visit:
|
||||
> https://tvheadend.org/projects/tvheadend/wiki/Building
|
||||
> https://tvheadend.org/projects/tvheadend/wiki/Packaging
|
||||
> https://tvheadend.org/projects/tvheadend/wiki/Git
|
||||
|
|
1148
data/conf/charset
1148
data/conf/charset
File diff suppressed because it is too large
Load diff
|
@ -24,6 +24,7 @@
|
|||
#include <pthread.h>
|
||||
#include "htsmsg.h"
|
||||
#include "psi.h"
|
||||
#include "tvhpoll.h"
|
||||
|
||||
struct service;
|
||||
struct th_dvb_table;
|
||||
|
@ -204,7 +205,7 @@ typedef struct th_dvb_adapter {
|
|||
|
||||
th_dvb_mux_instance_t *tda_mux_epg;
|
||||
|
||||
int tda_table_epollfd;
|
||||
tvhpoll_t *tda_table_pd;
|
||||
|
||||
uint32_t tda_enabled;
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "epggrab.h"
|
||||
#include "diseqc.h"
|
||||
#include "atomic.h"
|
||||
#include "tvhpoll.h"
|
||||
|
||||
#if ENABLE_EPOLL
|
||||
#include <sys/epoll.h>
|
||||
|
@ -1029,14 +1030,8 @@ dvb_adapter_input_dvr(void *aux)
|
|||
int fd = -1, i, r, c, nfds, dmx = -1;
|
||||
uint8_t tsb[188 * 10];
|
||||
service_t *t;
|
||||
#if ENABLE_EPOLL
|
||||
int delay = 10;
|
||||
int efd;
|
||||
struct epoll_event ev;
|
||||
#elif ENABLE_KQUEUE
|
||||
int kfd;
|
||||
struct kevent ke;
|
||||
#endif
|
||||
tvhpoll_t *pd;
|
||||
tvhpoll_event_t ev[2];
|
||||
|
||||
/* Install RAW demux */
|
||||
if (tda->tda_rawmode) {
|
||||
|
@ -1052,40 +1047,25 @@ dvb_adapter_input_dvr(void *aux)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#if ENABLE_EPOLL
|
||||
/* Create poll */
|
||||
efd = epoll_create(2);
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
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);
|
||||
#elif ENABLE_KQUEUE
|
||||
/* Create kqueue */
|
||||
kfd = kqueue();
|
||||
EV_SET(&ke, tda->tda_dvr_pipe.rd, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
kevent(kfd, &ke, 1, NULL, 0, NULL);
|
||||
EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
kevent(kfd, &ke, 1, NULL, 0, NULL);
|
||||
#endif
|
||||
pd = tvhpoll_create(2);
|
||||
memset(ev, 0, sizeof(ev));
|
||||
ev[0].data.fd = ev[0].fd = tda->tda_dvr_pipe.rd;
|
||||
ev[0].events = TVHPOLL_IN;
|
||||
ev[1].data.fd = ev[1].fd = fd;
|
||||
ev[1].events = TVHPOLL_IN;
|
||||
tvhpoll_add(pd, ev, 2);
|
||||
|
||||
r = i = 0;
|
||||
while(1) {
|
||||
|
||||
/* Wait for input */
|
||||
#if ENABLE_EPOLL
|
||||
nfds = epoll_wait(efd, &ev, 1, delay);
|
||||
nfds = tvhpoll_wait(pd, ev, 1, -1);
|
||||
|
||||
/* No data */
|
||||
if (nfds < 1) continue;
|
||||
|
||||
/* Exit */
|
||||
if (ev.data.fd != fd) break;
|
||||
#elif ENABLE_KQUEUE
|
||||
nfds = kevent(kfd, NULL, 0, &ke, 1, NULL);
|
||||
if (nfds < 1) continue;
|
||||
#endif
|
||||
if (ev[0].data.fd != fd) break;
|
||||
|
||||
/* Read data */
|
||||
c = read(fd, tsb+r, sizeof(tsb)-r);
|
||||
|
@ -1166,11 +1146,7 @@ dvb_adapter_input_dvr(void *aux)
|
|||
|
||||
if(dmx != -1)
|
||||
close(dmx);
|
||||
#if ENABLE_EPOLL
|
||||
close(efd);
|
||||
#elif ENABLE_KQUEUE
|
||||
close(kfd);
|
||||
#endif
|
||||
tvhpoll_destroy(pd);
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -27,11 +27,11 @@
|
|||
#include <fcntl.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "dvb.h"
|
||||
#include "service.h"
|
||||
#include "tvhpoll.h"
|
||||
|
||||
/**
|
||||
* Install filters for a service
|
||||
|
@ -58,9 +58,9 @@ open_service(th_dvb_adapter_t *tda, service_t *s)
|
|||
if(fd == -1) {
|
||||
st->es_demuxer_fd = -1;
|
||||
tvhlog(LOG_ERR, "dvb",
|
||||
"\"%s\" unable to open demuxer \"%s\" for pid %d -- %s",
|
||||
s->s_identifier, tda->tda_demux_path,
|
||||
st->es_pid, strerror(errno));
|
||||
"\"%s\" unable to open demuxer \"%s\" for pid %d -- %s",
|
||||
s->s_identifier, tda->tda_demux_path,
|
||||
st->es_pid, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -73,9 +73,9 @@ open_service(th_dvb_adapter_t *tda, service_t *s)
|
|||
|
||||
if(ioctl(fd, DMX_SET_PES_FILTER, &dmx_param)) {
|
||||
tvhlog(LOG_ERR, "dvb",
|
||||
"\"%s\" unable to configure demuxer \"%s\" for pid %d -- %s",
|
||||
s->s_identifier, tda->tda_demux_path,
|
||||
st->es_pid, strerror(errno));
|
||||
"\"%s\" unable to configure demuxer \"%s\" for pid %d -- %s",
|
||||
s->s_identifier, tda->tda_demux_path,
|
||||
st->es_pid, strerror(errno));
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ static void
|
|||
open_table(th_dvb_mux_instance_t *tdmi, th_dvb_table_t *tdt)
|
||||
{
|
||||
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
|
||||
struct epoll_event e;
|
||||
tvhpoll_event_t ev;
|
||||
static int tdt_id_tally;
|
||||
|
||||
tdt->tdt_fd = tvh_open(tda->tda_demux_path, O_RDWR, 0);
|
||||
|
@ -122,10 +122,11 @@ open_table(th_dvb_mux_instance_t *tdmi, th_dvb_table_t *tdt)
|
|||
|
||||
tdt->tdt_id = ++tdt_id_tally;
|
||||
|
||||
e.events = EPOLLIN;
|
||||
e.data.u64 = ((uint64_t)tdt->tdt_fd << 32) | tdt->tdt_id;
|
||||
ev.fd = tdt->tdt_fd;
|
||||
ev.events = TVHPOLL_IN;
|
||||
ev.data.u64 = ((uint64_t)tdt->tdt_fd << 32) | tdt->tdt_id;
|
||||
|
||||
if(epoll_ctl(tda->tda_table_epollfd, EPOLL_CTL_ADD, tdt->tdt_fd, &e)) {
|
||||
if(tvhpoll_add(tda->tda_table_pd, &ev, 1) != 0) {
|
||||
close(tdt->tdt_fd);
|
||||
tdt->tdt_fd = -1;
|
||||
} else {
|
||||
|
@ -136,13 +137,13 @@ open_table(th_dvb_mux_instance_t *tdmi, th_dvb_table_t *tdt)
|
|||
fp.filter.mask[0] = tdt->tdt_mask;
|
||||
|
||||
if(tdt->tdt_flags & TDT_CRC)
|
||||
fp.flags |= DMX_CHECK_CRC;
|
||||
fp.flags |= DMX_CHECK_CRC;
|
||||
fp.flags |= DMX_IMMEDIATE_START;
|
||||
fp.pid = tdt->tdt_pid;
|
||||
|
||||
if(ioctl(tdt->tdt_fd, DMX_SET_FILTER, &fp)) {
|
||||
close(tdt->tdt_fd);
|
||||
tdt->tdt_fd = -1;
|
||||
close(tdt->tdt_fd);
|
||||
tdt->tdt_fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,10 +160,12 @@ static void
|
|||
tdt_close_fd(th_dvb_mux_instance_t *tdmi, th_dvb_table_t *tdt)
|
||||
{
|
||||
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
|
||||
tvhpoll_event_t ev;
|
||||
|
||||
assert(tdt->tdt_fd != -1);
|
||||
|
||||
epoll_ctl(tda->tda_table_epollfd, EPOLL_CTL_DEL, tdt->tdt_fd, NULL);
|
||||
ev.fd = tdt->tdt_fd;
|
||||
tvhpoll_rem(tda->tda_table_pd, &ev, 1);
|
||||
close(tdt->tdt_fd);
|
||||
|
||||
tdt->tdt_fd = -1;
|
||||
|
@ -178,51 +181,48 @@ static void *
|
|||
dvb_table_input(void *aux)
|
||||
{
|
||||
th_dvb_adapter_t *tda = aux;
|
||||
int r, i, tid, fd, x;
|
||||
struct epoll_event ev[1];
|
||||
int r, tid, fd, x;
|
||||
uint8_t sec[4096];
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
th_dvb_table_t *tdt;
|
||||
int64_t cycle_barrier = 0;
|
||||
tvhpoll_event_t ev;
|
||||
|
||||
while(1) {
|
||||
x = epoll_wait(tda->tda_table_epollfd, ev, sizeof(ev) / sizeof(ev[0]), -1);
|
||||
x = tvhpoll_wait(tda->tda_table_pd, &ev, 1, -1);
|
||||
if (x != 1) continue;
|
||||
|
||||
for(i = 0; i < x; i++) {
|
||||
|
||||
tid = ev[i].data.u64 & 0xffffffff;
|
||||
fd = ev[i].data.u64 >> 32;
|
||||
tid = ev.data.u64 & 0xffffffff;
|
||||
fd = ev.data.u64 >> 32;
|
||||
|
||||
if(!(ev[i].events & EPOLLIN))
|
||||
continue;
|
||||
if(!(ev.events & TVHPOLL_IN))
|
||||
continue;
|
||||
|
||||
if((r = read(fd, sec, sizeof(sec))) < 3)
|
||||
continue;
|
||||
if((r = read(fd, sec, sizeof(sec))) < 3)
|
||||
continue;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
if((tdmi = tda->tda_mux_current) != NULL) {
|
||||
LIST_FOREACH(tdt, &tdmi->tdmi_tables, tdt_link)
|
||||
if(tdt->tdt_id == tid)
|
||||
break;
|
||||
pthread_mutex_lock(&global_lock);
|
||||
if((tdmi = tda->tda_mux_current) != NULL) {
|
||||
LIST_FOREACH(tdt, &tdmi->tdmi_tables, tdt_link)
|
||||
if(tdt->tdt_id == tid)
|
||||
break;
|
||||
|
||||
if(tdt != NULL) {
|
||||
dvb_table_dispatch(sec, r, tdt);
|
||||
if(tdt != NULL) {
|
||||
dvb_table_dispatch(sec, r, tdt);
|
||||
|
||||
/* Any tables pending (that wants a filter/fd), close this one */
|
||||
if(TAILQ_FIRST(&tdmi->tdmi_table_queue) != NULL &&
|
||||
cycle_barrier < getmonoclock()) {
|
||||
tdt_close_fd(tdmi, tdt);
|
||||
cycle_barrier = getmonoclock() + 100000;
|
||||
tdt = TAILQ_FIRST(&tdmi->tdmi_table_queue);
|
||||
assert(tdt != NULL);
|
||||
TAILQ_REMOVE(&tdmi->tdmi_table_queue, tdt, tdt_pending_link);
|
||||
|
||||
open_table(tdmi, tdt);
|
||||
}
|
||||
}
|
||||
/* Any tables pending (that wants a filter/fd), close this one */
|
||||
if(TAILQ_FIRST(&tdmi->tdmi_table_queue) != NULL &&
|
||||
cycle_barrier < getmonoclock()) {
|
||||
tdt_close_fd(tdmi, tdt);
|
||||
cycle_barrier = getmonoclock() + 100000;
|
||||
tdt = TAILQ_FIRST(&tdmi->tdmi_table_queue);
|
||||
assert(tdt != NULL);
|
||||
TAILQ_REMOVE(&tdmi->tdmi_table_queue, tdt, tdt_pending_link);
|
||||
open_table(tdmi, tdt);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -232,11 +232,13 @@ static void
|
|||
close_table(th_dvb_mux_instance_t *tdmi, th_dvb_table_t *tdt)
|
||||
{
|
||||
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
|
||||
tvhpoll_event_t ev;
|
||||
|
||||
if(tdt->tdt_fd == -1) {
|
||||
TAILQ_REMOVE(&tdmi->tdmi_table_queue, tdt, tdt_pending_link);
|
||||
} else {
|
||||
epoll_ctl(tda->tda_table_epollfd, EPOLL_CTL_DEL, tdt->tdt_fd, NULL);
|
||||
ev.fd = tdt->tdt_fd;
|
||||
tvhpoll_rem(tda->tda_table_pd, &ev, 1);
|
||||
close(tdt->tdt_fd);
|
||||
}
|
||||
}
|
||||
|
@ -253,7 +255,7 @@ dvb_input_filtered_setup(th_dvb_adapter_t *tda)
|
|||
tda->tda_close_table = close_table;
|
||||
|
||||
pthread_t ptid;
|
||||
tda->tda_table_epollfd = epoll_create(50);
|
||||
tda->tda_table_pd = tvhpoll_create(50);
|
||||
pthread_create(&ptid, NULL, dvb_table_input, tda);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
@ -40,6 +39,7 @@
|
|||
#include "tsdemux.h"
|
||||
#include "psi.h"
|
||||
#include "settings.h"
|
||||
#include "tvhpoll.h"
|
||||
|
||||
#if defined(PLATFORM_LINUX)
|
||||
#include <linux/netdevice.h>
|
||||
|
@ -52,8 +52,8 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
static int iptv_thread_running;
|
||||
static int iptv_epollfd;
|
||||
static int iptv_thread_running;
|
||||
static tvhpoll_t *iptv_poll;
|
||||
static pthread_mutex_t iptv_recvmutex;
|
||||
|
||||
struct service_list iptv_all_services; /* All IPTV services */
|
||||
|
@ -137,11 +137,11 @@ iptv_thread(void *aux)
|
|||
{
|
||||
int nfds, fd, r, j, hlen;
|
||||
uint8_t tsb[65536], *buf;
|
||||
struct epoll_event ev;
|
||||
tvhpoll_event_t ev;
|
||||
service_t *t;
|
||||
|
||||
while(1) {
|
||||
nfds = epoll_wait(iptv_epollfd, &ev, 1, -1);
|
||||
nfds = tvhpoll_wait(iptv_poll, &ev, 1, -1);
|
||||
if(nfds == -1) {
|
||||
tvhlog(LOG_ERR, "IPTV", "epoll() error -- %s, sleeping 1 second",
|
||||
strerror(errno));
|
||||
|
@ -220,13 +220,13 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start)
|
|||
struct sockaddr_in sin;
|
||||
struct sockaddr_in6 sin6;
|
||||
struct ifreq ifr;
|
||||
struct epoll_event ev;
|
||||
tvhpoll_event_t ev;
|
||||
|
||||
assert(t->s_iptv_fd == -1);
|
||||
|
||||
if(iptv_thread_running == 0) {
|
||||
iptv_thread_running = 1;
|
||||
iptv_epollfd = epoll_create(10);
|
||||
iptv_poll = tvhpoll_create(10);
|
||||
pthread_create(&tid, NULL, iptv_thread, NULL);
|
||||
}
|
||||
|
||||
|
@ -345,9 +345,10 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start)
|
|||
resize, strerror(errno));
|
||||
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.events = EPOLLIN;
|
||||
ev.events = TVHPOLL_IN;
|
||||
ev.fd = fd;
|
||||
ev.data.fd = fd;
|
||||
if(epoll_ctl(iptv_epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
|
||||
if(tvhpoll_add(iptv_poll, &ev, 1) == -1) {
|
||||
tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot add to epoll set -- %s",
|
||||
t->s_identifier, strerror(errno));
|
||||
close(fd);
|
||||
|
@ -451,6 +452,7 @@ iptv_service_stop(service_t *t)
|
|||
#endif
|
||||
}
|
||||
close(t->s_iptv_fd); // Automatically removes fd from epoll set
|
||||
// TODO: this is an issue
|
||||
|
||||
t->s_iptv_fd = -1;
|
||||
}
|
||||
|
|
96
src/tcp.c
96
src/tcp.c
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include <pthread.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <poll.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
@ -34,6 +33,7 @@
|
|||
|
||||
#include "tcp.h"
|
||||
#include "tvheadend.h"
|
||||
#include "tvhpoll.h"
|
||||
|
||||
int tcp_preferred_address_family = AF_INET;
|
||||
|
||||
|
@ -144,16 +144,16 @@ tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize,
|
|||
|
||||
r = poll(&pfd, 1, timeout * 1000);
|
||||
if(r == 0) {
|
||||
/* Timeout */
|
||||
snprintf(errbuf, errbufsize, "Connection attempt timed out");
|
||||
close(fd);
|
||||
return -1;
|
||||
/* Timeout */
|
||||
snprintf(errbuf, errbufsize, "Connection attempt timed out");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(r == -1) {
|
||||
snprintf(errbuf, errbufsize, "poll() error: %s", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
snprintf(errbuf, errbufsize, "poll() error: %s", strerror(errno));
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen);
|
||||
|
@ -331,7 +331,7 @@ tcp_read_timeout(int fd, void *buf, size_t len, int timeout)
|
|||
x = recv(fd, buf + tot, len - tot, MSG_DONTWAIT);
|
||||
if(x == -1) {
|
||||
if(errno == EAGAIN)
|
||||
continue;
|
||||
continue;
|
||||
return errno;
|
||||
}
|
||||
|
||||
|
@ -373,7 +373,7 @@ tcp_get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen)
|
|||
/**
|
||||
*
|
||||
*/
|
||||
static int tcp_server_epoll_fd;
|
||||
static tvhpoll_t *tcp_server_poll;
|
||||
|
||||
typedef struct tcp_server {
|
||||
tcp_server_callback_t *start;
|
||||
|
@ -438,8 +438,8 @@ tcp_server_start(void *aux)
|
|||
static void *
|
||||
tcp_server_loop(void *aux)
|
||||
{
|
||||
int r, i;
|
||||
struct epoll_event ev[1];
|
||||
int r;
|
||||
tvhpoll_event_t ev;
|
||||
tcp_server_t *ts;
|
||||
tcp_server_launch_t *tsl;
|
||||
pthread_attr_t attr;
|
||||
|
@ -450,46 +450,45 @@ tcp_server_loop(void *aux)
|
|||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
while(1) {
|
||||
r = epoll_wait(tcp_server_epoll_fd, ev, sizeof(ev) / sizeof(ev[0]), -1);
|
||||
r = tvhpoll_wait(tcp_server_poll, &ev, 1, -1);
|
||||
if(r == -1) {
|
||||
perror("tcp_server: epoll_wait");
|
||||
perror("tcp_server: tchpoll_wait");
|
||||
continue;
|
||||
}
|
||||
|
||||
for(i = 0; i < r; i++) {
|
||||
ts = ev[i].data.ptr;
|
||||
if (r == 0) continue;
|
||||
|
||||
if(ev[i].events & EPOLLHUP) {
|
||||
close(ts->serverfd);
|
||||
free(ts);
|
||||
continue;
|
||||
}
|
||||
ts = ev.data.ptr;
|
||||
|
||||
if(ev[i].events & EPOLLIN) {
|
||||
tsl = malloc(sizeof(tcp_server_launch_t));
|
||||
tsl->start = ts->start;
|
||||
tsl->opaque = ts->opaque;
|
||||
slen = sizeof(struct sockaddr_storage);
|
||||
if(ev.events & TVHPOLL_HUP) {
|
||||
close(ts->serverfd);
|
||||
free(ts);
|
||||
continue;
|
||||
}
|
||||
|
||||
tsl->fd = accept(ts->serverfd,
|
||||
(struct sockaddr *)&tsl->peer, &slen);
|
||||
if(tsl->fd == -1) {
|
||||
perror("accept");
|
||||
free(tsl);
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
if(ev.events & TVHPOLL_IN) {
|
||||
tsl = malloc(sizeof(tcp_server_launch_t));
|
||||
tsl->start = ts->start;
|
||||
tsl->opaque = ts->opaque;
|
||||
slen = sizeof(struct sockaddr_storage);
|
||||
|
||||
tsl->fd = accept(ts->serverfd,
|
||||
(struct sockaddr *)&tsl->peer, &slen);
|
||||
if(tsl->fd == -1) {
|
||||
perror("accept");
|
||||
free(tsl);
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
slen = sizeof(struct sockaddr_storage);
|
||||
if(getsockname(tsl->fd, (struct sockaddr *)&tsl->self, &slen)) {
|
||||
close(tsl->fd);
|
||||
free(tsl);
|
||||
continue;
|
||||
}
|
||||
slen = sizeof(struct sockaddr_storage);
|
||||
if(getsockname(tsl->fd, (struct sockaddr *)&tsl->self, &slen)) {
|
||||
close(tsl->fd);
|
||||
free(tsl);
|
||||
continue;
|
||||
}
|
||||
|
||||
pthread_create(&tid, &attr, tcp_server_start, tsl);
|
||||
}
|
||||
pthread_create(&tid, &attr, tcp_server_start, tsl);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
@ -502,14 +501,14 @@ void *
|
|||
tcp_server_create(const char *bindaddr, int port, tcp_server_callback_t *start, void *opaque)
|
||||
{
|
||||
int fd, x;
|
||||
struct epoll_event e;
|
||||
tvhpoll_event_t ev;
|
||||
tcp_server_t *ts;
|
||||
struct addrinfo hints, *res, *ressave, *use = NULL;
|
||||
char *portBuf = (char*)malloc(6);
|
||||
int one = 1;
|
||||
int zero = 0;
|
||||
|
||||
memset(&e, 0, sizeof(e));
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
|
||||
snprintf(portBuf, 6, "%d", port);
|
||||
|
||||
|
@ -570,9 +569,10 @@ tcp_server_create(const char *bindaddr, int port, tcp_server_callback_t *start,
|
|||
ts->start = start;
|
||||
ts->opaque = opaque;
|
||||
|
||||
e.events = EPOLLIN;
|
||||
e.data.ptr = ts;
|
||||
epoll_ctl(tcp_server_epoll_fd, EPOLL_CTL_ADD, fd, &e);
|
||||
ev.fd = fd;
|
||||
ev.events = TVHPOLL_IN;
|
||||
ev.data.ptr = ts;
|
||||
tvhpoll_add(tcp_server_poll, &ev, 1);
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
@ -588,7 +588,7 @@ tcp_server_init(int opt_ipv6)
|
|||
if(opt_ipv6)
|
||||
tcp_preferred_address_family = AF_INET6;
|
||||
|
||||
tcp_server_epoll_fd = epoll_create(10);
|
||||
tcp_server_poll = tvhpoll_create(10);
|
||||
pthread_create(&tid, NULL, tcp_server_loop, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "timeshift.h"
|
||||
#include "timeshift/private.h"
|
||||
#include "atomic.h"
|
||||
#include "tvhpoll.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -416,26 +417,13 @@ void *timeshift_reader ( void *p )
|
|||
timeshift_index_iframe_t *tsi = NULL;
|
||||
streaming_skip_t *skip = NULL;
|
||||
time_t last_status = 0;
|
||||
#if ENABLE_EPOLL
|
||||
int efd;
|
||||
struct epoll_event ev = { 0 };
|
||||
#elif ENABLE_KQUEUE
|
||||
int kfd;
|
||||
struct kevent ke;
|
||||
#endif
|
||||
tvhpoll_t *pd;
|
||||
tvhpoll_event_t ev = { 0 };
|
||||
|
||||
#if ENABLE_EPOLL
|
||||
/* Poll */
|
||||
efd = epoll_create(1);
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = ts->rd_pipe.rd;
|
||||
epoll_ctl(efd, EPOLL_CTL_ADD, ev.data.fd, &ev);
|
||||
#elif ENABLE_KQUEUE
|
||||
/* kqueue */
|
||||
kfd = kqueue();
|
||||
EV_SET(&ke, ts->rd_pipe.rd, EVFILT_READ, EV_ADD, 0, 0, NULL);
|
||||
kevent(kfd, &ke, 1, NULL, 0, NULL);
|
||||
#endif
|
||||
pd = tvhpoll_create(1);
|
||||
ev.fd = ts->rd_pipe.rd;
|
||||
ev.events = TVHPOLL_IN;
|
||||
tvhpoll_add(pd, &ev, 1);
|
||||
|
||||
/* Output */
|
||||
while (run) {
|
||||
|
@ -447,11 +435,7 @@ void *timeshift_reader ( void *p )
|
|||
|
||||
/* Wait for data */
|
||||
if(wait)
|
||||
#if ENABLE_EPOLL
|
||||
nfds = epoll_wait(efd, &ev, 1, wait);
|
||||
#elif ENABLE_KQUEUE
|
||||
nfds = kevent(kfd, NULL, 0, &ke, 1, NULL);
|
||||
#endif
|
||||
nfds = tvhpoll_wait(pd, &ev, 1, wait);
|
||||
else
|
||||
nfds = 0;
|
||||
wait = -1;
|
||||
|
@ -826,11 +810,7 @@ void *timeshift_reader ( void *p )
|
|||
}
|
||||
|
||||
/* Cleanup */
|
||||
#if ENABLE_EPOLL
|
||||
close(efd);
|
||||
#elif ENABLE_KQUEUE
|
||||
close(kfd);
|
||||
#endif
|
||||
tvhpoll_destroy(pd);
|
||||
if (fd != -1) close(fd);
|
||||
if (sm) streaming_msg_free(sm);
|
||||
if (ctrl) streaming_msg_free(ctrl);
|
||||
|
|
|
@ -106,13 +106,16 @@ int tvhpoll_add
|
|||
struct epoll_event ev;
|
||||
for (i = 0; i < num; i++) {
|
||||
memset(&ev, 0, sizeof(ev));
|
||||
ev.data.fd = evs[i].fd;
|
||||
ev.data.u64 = evs[i].data.u64;
|
||||
if (evs[i].events & TVHPOLL_IN) ev.events |= EPOLLIN;
|
||||
if (evs[i].events & TVHPOLL_OUT) ev.events |= EPOLLOUT;
|
||||
if (evs[i].events & TVHPOLL_PRI) ev.events |= EPOLLPRI;
|
||||
if (evs[i].events & TVHPOLL_ERR) ev.events |= EPOLLERR;
|
||||
epoll_ctl(tp->fd, EPOLL_CTL_ADD, evs[i].fd, &ev);
|
||||
if (evs[i].events & TVHPOLL_HUP) ev.events |= EPOLLHUP;
|
||||
if (epoll_ctl(tp->fd, EPOLL_CTL_ADD, evs[i].fd, &ev) != 0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
#elif ENABLE_KQUEUE
|
||||
int i;
|
||||
uint32_t fflags;
|
||||
|
@ -121,12 +124,11 @@ int tvhpoll_add
|
|||
fflags = 0;
|
||||
if (evs[i].events & TVHPOLL_OUT) fflags |= EVFILT_WRITE;
|
||||
if (evs[i].events & TVHPOLL_IN) fflags |= EVFILT_READ;
|
||||
EV_SET(tp->ev+i, evs[i].fd, fflags, EV_ADD, 0, 0, NULL);
|
||||
EV_SET(tp->ev+i, evs[i].fd, fflags, EV_ADD, 0, 0, evs[i].data.u64);
|
||||
}
|
||||
kevent(tp->fd, tp->ev, num, NULL, 0, NULL);
|
||||
return kevent(tp->fd, tp->ev, num, NULL, 0, NULL);
|
||||
#else
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tvhpoll_rem
|
||||
|
@ -155,12 +157,13 @@ int tvhpoll_wait
|
|||
#if ENABLE_EPOLL
|
||||
nfds = epoll_wait(tp->fd, tp->ev, num, ms);
|
||||
for (i = 0; i < nfds; i++) {
|
||||
evs[i].fd = tp->ev[i].data.fd;
|
||||
evs[i].events = 0;
|
||||
evs[i].data.u64 = tp->ev[i].data.u64;
|
||||
evs[i].events = 0;
|
||||
if (tp->ev[i].events & EPOLLIN) evs[i].events |= TVHPOLL_IN;
|
||||
if (tp->ev[i].events & EPOLLOUT) evs[i].events |= TVHPOLL_OUT;
|
||||
if (tp->ev[i].events & EPOLLERR) evs[i].events |= TVHPOLL_ERR;
|
||||
if (tp->ev[i].events & EPOLLPRI) evs[i].events |= TVHPOLL_PRI;
|
||||
if (tp->ev[i].events & EPOLLHUP) evs[i].events |= TVHPOLL_HUP;
|
||||
}
|
||||
#elif ENABLE_KQUEUE
|
||||
struct timespec tm, *to = NULL;
|
||||
|
@ -171,10 +174,12 @@ int tvhpoll_wait
|
|||
}
|
||||
nfds = kevent(tp->fd, NULL, 0, tp->ev, num, to);
|
||||
for (i = 0; i < nfds; i++) {
|
||||
evs[i].fd = tp->ev[i].ident;
|
||||
evs[i].events = 0;
|
||||
evs[i].fd = tp->ev[i].ident;
|
||||
evs[i].events = 0;
|
||||
evs[i].data.u64 = tp->ev[i].udata;
|
||||
if (tp->ev[i].fflags & EVFILT_WRITE) evs[i].events |= TVHPOLL_OUT;
|
||||
if (tp->ev[i].fflags & EVFILT_READ) evs[i].events |= TVHPOLL_IN;
|
||||
if (tp->ev[i].flags & EV_EOF) evs[i].events |= TVHPOLL_HUP;
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
|
|
@ -18,22 +18,29 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TVH_POLL_H__
|
||||
#define __TVH_POLL_H_
|
||||
#ifndef __TVHPOLL_H__
|
||||
#define __TVHPOLL_H__
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct tvhpoll tvhpoll_t;
|
||||
typedef struct tvhpoll_event
|
||||
{
|
||||
int fd;
|
||||
int events;
|
||||
int fd; // input
|
||||
int events;
|
||||
union {
|
||||
void *ptr;
|
||||
uint64_t u64;
|
||||
uint32_t u32;
|
||||
int fd;
|
||||
} data;
|
||||
} tvhpoll_event_t;
|
||||
|
||||
#define TVHPOLL_IN 0x01
|
||||
#define TVHPOLL_OUT 0x02
|
||||
#define TVHPOLL_PRI 0x04
|
||||
#define TVHPOLL_ERR 0x08
|
||||
#define TVHPOLL_HUP 0x10
|
||||
|
||||
tvhpoll_t *tvhpoll_create ( size_t num );
|
||||
void tvhpoll_destroy ( tvhpoll_t *tp );
|
||||
|
@ -44,4 +51,4 @@ int tvhpoll_rem
|
|||
int tvhpoll_wait
|
||||
( tvhpoll_t *tp, tvhpoll_event_t *evs, size_t num, int ms );
|
||||
|
||||
#endif /* __TVH_POLL_H__ */
|
||||
#endif /* __TVHPOLL_H__ */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* tvheadend, WEBUI / HTML user interface
|
||||
* Copyright (C) 2008 Andreas Öman
|
||||
* Copyright (C) 2008 Andreas <EFBFBD>man
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -422,20 +422,20 @@ page_status(http_connection_t *hc,
|
|||
|
||||
html_escape(buf, lang_str_get(de->de_title, NULL), sizeof(buf));
|
||||
htsbuf_qprintf(hq,
|
||||
"<recording>"
|
||||
"<start>"
|
||||
"<date>%d/%02d/%02d</date>"
|
||||
"<time>%02d:%02d</time>"
|
||||
"<unixtime>%"PRItime_t"</unixtime>"
|
||||
"<extra_start>%"PRItime_t"</extra_start>"
|
||||
"</start>"
|
||||
"<stop>"
|
||||
"<date>%d/%02d/%02d</date>"
|
||||
"<time>%02d:%02d</time>"
|
||||
"<unixtime>%"PRItime_t"</unixtime>"
|
||||
"<extra_stop>%"PRItime_t"</extra_stop>"
|
||||
"</stop>"
|
||||
"<title>%s</title>",
|
||||
"<recording>\n"
|
||||
"<start>\n"
|
||||
"<date>%d/%02d/%02d</date>\n"
|
||||
"<time>%02d:%02d</time>\n"
|
||||
"<unixtime>%"PRItime_t"</unixtime>\n"
|
||||
"<extra_start>%"PRItime_t"</extra_start>\n"
|
||||
"</start>\n"
|
||||
"<stop>\n"
|
||||
"<date>%d/%02d/%02d</date>\n"
|
||||
"<time>%02d:%02d</time>\n"
|
||||
"<unixtime>%"PRItime_t"</unixtime>\n"
|
||||
"<extra_stop>%"PRItime_t"</extra_stop>\n"
|
||||
"</stop>\n"
|
||||
"<title>%s</title>\n",
|
||||
a.tm_year + 1900, a.tm_mon + 1, a.tm_mday,
|
||||
a.tm_hour, a.tm_min,
|
||||
de->de_start,
|
||||
|
@ -448,14 +448,14 @@ page_status(http_connection_t *hc,
|
|||
|
||||
rstatus = val2str(de->de_sched_state, recstatustxt);
|
||||
html_escape(buf, rstatus, sizeof(buf));
|
||||
htsbuf_qprintf(hq, "<status>%s</status></recording>\n", buf);
|
||||
htsbuf_qprintf(hq, "<status>%s</status>\n</recording>\n", buf);
|
||||
cc++;
|
||||
timeleft = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((cc==0) && (timeleft < INT_MAX)) {
|
||||
htsbuf_qprintf(hq, "<recording><next>%d</next></recording>\n",timeleft);
|
||||
htsbuf_qprintf(hq, "<recording>\n<next>%d</next>\n</recording>\n",timeleft);
|
||||
}
|
||||
|
||||
dvr_query_free(&dqr);
|
||||
|
|
Loading…
Add table
Reference in a new issue