diff --git a/Makefile b/Makefile index b3a6a7ae..1ae7e9ef 100644 --- a/Makefile +++ b/Makefile @@ -114,7 +114,8 @@ SRCS = src/version.c \ src/lang_codes.c \ src/lang_str.c \ src/imagecache.c \ - src/tvhtime.c + src/tvhtime.c \ + src/tvhpoll.c SRCS += src/epggrab/module.c\ src/epggrab/channel.c\ diff --git a/src/tvhpoll.c b/src/tvhpoll.c new file mode 100644 index 00000000..6b7e92df --- /dev/null +++ b/src/tvhpoll.c @@ -0,0 +1,181 @@ +/* + * TVheadend - poll/select wrapper + * + * Copyright (C) 2013 Adam Sutton + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#define ENABLE_EPOLL 1 + +#include "tvheadend.h" +#include "tvhpoll.h" + +#include +#include +#include +#include +#include +#if ENABLE_EPOLL +#include +#elif ENABLE_KQUEUE +#include +#include +#endif + +#if ENABLE_EPOLL +#define EV_SIZE sizeof(struct epoll_event) +#elif ENABLE_KQUEUE +#define EV_SIZE sizeof(struct kevent) +#endif + +struct tvhpoll +{ +#if ENABLE_EPOLL + int fd; + struct epoll_event *ev; + int nev; +#elif ENABLE_KQUEUE + int fd; + struct kevent *ev; + int nev; +#else +#endif +}; + +static void +tvhpoll_alloc ( tvhpoll_t *tp, int n ) +{ +#if ENABLE_EPOLL || ENABLE_KQUEUE + if (n > tp->nev) { + tp->ev = realloc(tp->ev, n * EV_SIZE); + tp->nev = n; + } +#else +#endif +} + +tvhpoll_t * +tvhpoll_create ( size_t n ) +{ + int fd; +#if ENABLE_EPOLL + if ((fd = epoll_create(n)) < 0) { + tvhlog(LOG_ERR, "tvhpoll", "failed to create epoll [%s]", + strerror(errno)); + return NULL; + } +#elif ENABLE_KQUEUE + if ((fd = kqueue()) < 0) { + tvhlog(LOG_ERR, "tvhpoll", "failed to create kqueue [%s]", + strerror(errno)); + return NULL; + } +#else +#endif + tvhpoll_t *tp = calloc(1, sizeof(tvhpoll_t)); + tp->fd = fd; + tvhpoll_alloc(tp, n); + return tp; +} + +void tvhpoll_destroy ( tvhpoll_t *tp ) +{ +#if ENABLE_EPOLL || ENABLE_KQUEUE + free(tp->ev); + close(tp->fd); +#endif + free(tp); +} + +int tvhpoll_add + ( tvhpoll_t *tp, tvhpoll_event_t *evs, size_t num ) +{ +#if ENABLE_EPOLL + int i; + struct epoll_event ev; + for (i = 0; i < num; i++) { + memset(&ev, 0, sizeof(ev)); + ev.data.fd = evs[i].fd; + 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); + } +#elif ENABLE_KQUEUE + int i; + uint32_t fflags; + tvhpoll_alloc(tp, num); + for (i = 0; i < num; i++) { + if (evs[i] & TVHPOLL_OUT) fflags |= EVFILT_WRITE; + if (evs[i] & TVHPOLL_IN) fflags |= EVFILT_READ; + EV_SET(tp->ev+i, evs[i].fd, fflags, EV_ADD, 0, 0, NULL); + } + kevent(tp->fd, tp->ev, num, NULL, 0, NULL); +#else +#endif + return 0; +} + +int tvhpoll_rem + ( tvhpoll_t *tp, tvhpoll_event_t *evs, size_t num ) +{ + tvhpoll_alloc(tp, num); +#if ENABLE_EPOLL + int i; + for (i = 0; i < num; i++) + epoll_ctl(tp->fd, EPOLL_CTL_DEL, evs[i].fd, NULL); +#elif ENABLE_KQUEUE + int i; + for (i = 0; i < num; i++) + EV_SET(tp->ev+i, evs[i].fd, 0, EV_DEL, 0, 0, NULL); + kevent(tp->fd, tp->ev, num, NULL, 0, NULL); +#else +#endif + return 0; +} + +int tvhpoll_wait + ( tvhpoll_t *tp, tvhpoll_event_t *evs, size_t num, int ms ) +{ + int nfds = 0, i; + tvhpoll_alloc(tp, num); +#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; + 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; + } +#elif ENABLE_KQUEUE + struct timespec tm, *to = NULL; + if (ms) { + tm.tv_sec = ms / 1000; + tm.tv_nsec = (ms % 1000) * 1000000LL; + to = &tm; + } + 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; + if (tp->ev[i].ffilt & EVFILT_WRITE) evs[i].events |= TVHPOLL_OUT; + if (tp->ev[i].ffilt & EVFILT_READ) evs[i].events |= TVHPOLL_IN; + } +#else +#endif + return nfds; +} diff --git a/src/tvhpoll.h b/src/tvhpoll.h new file mode 100644 index 00000000..afdbfbc9 --- /dev/null +++ b/src/tvhpoll.h @@ -0,0 +1,47 @@ + +/* + * TVheadend - poll/select wrapper + * + * Copyright (C) 2013 Adam Sutton + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TVH_POLL_H__ +#define __TVH_POLL_H_ + +#include + +typedef struct tvhpoll tvhpoll_t; +typedef struct tvhpoll_event +{ + int fd; + int events; +} tvhpoll_event_t; + +#define TVHPOLL_IN 0x01 +#define TVHPOLL_OUT 0x02 +#define TVHPOLL_PRI 0x04 +#define TVHPOLL_ERR 0x08 + +tvhpoll_t *tvhpoll_create ( size_t num ); +void tvhpoll_destroy ( tvhpoll_t *tp ); +int tvhpoll_add + ( tvhpoll_t *tp, tvhpoll_event_t *evs, size_t num ); +int tvhpoll_rem + ( tvhpoll_t *tp, tvhpoll_event_t *evs, size_t num ); +int tvhpoll_wait + ( tvhpoll_t *tp, tvhpoll_event_t *evs, size_t num, int ms ); + +#endif /* __TVH_POLL_H__ */