Merge remote-tracking branch 'upstream/master' after all FreeBSD

related changes have been merged from upstream.
This commit is contained in:
Bernhard Froehlich 2013-06-02 11:30:50 +02:00
commit 7082d8da77
12 changed files with 942 additions and 617 deletions

14
README
View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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;

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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

View file

@ -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__ */

View file

@ -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);