Merge remote-tracking branch 'origin/pr/329'

Conflicts:
	src/tvheadend.h
This commit is contained in:
Adam Sutton 2014-03-05 16:22:03 +00:00
commit ae2ba4b6cd
93 changed files with 1270 additions and 292 deletions

View file

@ -520,6 +520,7 @@ access_entry_destroy(access_entry_t *ae)
free(ae->ae_id);
free(ae->ae_username);
free(ae->ae_password);
free(ae->ae_comment);
TAILQ_REMOVE(&access_entries, ae, ae_link);
free(ae);
}
@ -769,3 +770,13 @@ access_init(int createdefault, int noacl)
htsmsg_destroy(m);
}
}
void
access_done(void)
{
access_entry_t *ae;
dtable_delete("accesscontrol");
while ((ae = TAILQ_FIRST(&access_entries)) != NULL)
access_entry_destroy(ae);
}

View file

@ -111,5 +111,6 @@ uint32_t access_get_by_addr(struct sockaddr *src);
*
*/
void access_init(int createdefault, int noacl);
void access_done(void);
#endif /* ACCESS_H_ */

View file

@ -29,6 +29,7 @@ typedef struct api_link {
} api_link_t;
RB_HEAD(,api_link) api_hook_tree;
SKEL_DECLARE(api_skel, api_link_t);
static int ah_cmp
( api_link_t *a, api_link_t *b )
@ -39,15 +40,15 @@ static int ah_cmp
void
api_register ( const api_hook_t *hook )
{
static api_link_t *t, *skel = NULL;
if (!skel)
skel = calloc(1, sizeof(api_link_t));
skel->hook = hook;
t = RB_INSERT_SORTED(&api_hook_tree, skel, link, ah_cmp);
if (t)
api_link_t *t;
SKEL_ALLOC(api_skel);
api_skel->hook = hook;
t = RB_INSERT_SORTED(&api_hook_tree, api_skel, link, ah_cmp);
if (t) {
tvherror("api", "trying to re-register subsystem");
else
skel = NULL;
} else {
SKEL_USED(api_skel);
}
}
void
@ -125,3 +126,14 @@ void api_init ( void )
api_status_init();
api_imagecache_init();
}
void api_done ( void )
{
api_link_t *t;
while ((t = RB_FIRST(&api_hook_tree)) != NULL) {
RB_REMOVE(&api_hook_tree, t, link);
free(t);
}
SKEL_FREE(api_skel);
}

View file

@ -56,6 +56,7 @@ int api_exec ( const char *subsystem, htsmsg_t *args, htsmsg_t **resp );
* Initialise
*/
void api_init ( void );
void api_done ( void );
void api_idnode_init ( void );
void api_input_init ( void );
void api_service_init ( void );

View file

@ -170,6 +170,8 @@ api_idnode_load_by_class
if (e)
htsmsg_add_msg(l, NULL, e);
}
free(is->is_array);
free(is);
}
*resp = htsmsg_create_map();
htsmsg_add_msg(*resp, "entries", l);

View file

@ -39,6 +39,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <signal.h>
#include <avahi-client/client.h>
#include <avahi-client/publish.h>
@ -54,6 +55,7 @@
static AvahiEntryGroup *group = NULL;
static char *name = NULL;
static AvahiSimplePoll *avahi_asp = NULL;
static void create_services(AvahiClient *c);
@ -247,14 +249,13 @@ client_callback(AvahiClient *c, AvahiClientState state, void *userdata)
static void *
avahi_thread(void *aux)
{
AvahiSimplePoll *asp = avahi_simple_poll_new();
const AvahiPoll *ap = avahi_simple_poll_get(asp);
const AvahiPoll *ap = avahi_simple_poll_get(avahi_asp);
name = avahi_strdup("Tvheadend");
avahi_client_new(ap, AVAHI_CLIENT_NO_FAIL, client_callback, NULL, NULL);
while((avahi_simple_poll_iterate(asp, -1)) != -1) {}
while(avahi_simple_poll_iterate(avahi_asp, -1) == 0);
return NULL;
@ -264,10 +265,19 @@ avahi_thread(void *aux)
/**
*
*/
pthread_t avahi_tid;
void
avahi_init(void)
{
pthread_t tid;
tvhthread_create(&tid, NULL, avahi_thread, NULL, 1);
avahi_asp = avahi_simple_poll_new();
tvhthread_create(&avahi_tid, NULL, avahi_thread, NULL, 0);
}
void
avahi_done(void)
{
avahi_simple_poll_quit(avahi_asp);
pthread_kill(avahi_tid, SIGTERM);
pthread_join(avahi_tid, NULL);
}

View file

@ -1 +1,7 @@
#ifdef CONFIG_AVAHI
void avahi_init(void);
void avahi_done(void);
#else
static inline void avahi_init(void) { }
static inline void avahi_done(void) { }
#endif

View file

@ -48,9 +48,12 @@ struct channel_tag_queue channel_tags;
static dtable_t *channeltags_dtable;
static void channel_tag_init ( void );
static void channel_tag_done ( void );
static channel_tag_t *channel_tag_find(const char *id, int create);
static void channel_tag_mapping_destroy(channel_tag_mapping_t *ctm,
int flags);
static void channel_tag_destroy(channel_tag_t *ct, int delconf);
#define CTM_DESTROY_UPDATE_TAG 0x1
#define CTM_DESTROY_UPDATE_CHANNEL 0x2
@ -74,7 +77,7 @@ channel_class_save ( idnode_t *self )
static void
channel_class_delete ( idnode_t *self )
{
channel_delete((channel_t*)self);
channel_delete((channel_t*)self, 1);
}
static const void *
@ -543,7 +546,7 @@ channel_create0
}
void
channel_delete ( channel_t *ch )
channel_delete ( channel_t *ch, int delconf )
{
th_subscription_t *s;
channel_tag_mapping_t *ctm;
@ -551,14 +554,15 @@ channel_delete ( channel_t *ch )
lock_assert(&global_lock);
tvhinfo("channel", "%s - deleting", channel_get_name(ch));
if (delconf)
tvhinfo("channel", "%s - deleting", channel_get_name(ch));
/* Tags */
while((ctm = LIST_FIRST(&ch->ch_ctms)) != NULL)
channel_tag_mapping_destroy(ctm, CTM_DESTROY_UPDATE_TAG);
/* DVR */
autorec_destroy_by_channel(ch);
autorec_destroy_by_channel(ch, delconf);
dvr_destroy_by_channel(ch);
/* Services */
@ -579,7 +583,8 @@ channel_delete ( channel_t *ch )
htsp_channel_delete(ch);
/* Settings */
hts_settings_remove("channel/%s", idnode_uuid_as_str(&ch->ch_id));
if (delconf)
hts_settings_remove("channel/%s", idnode_uuid_as_str(&ch->ch_id));
/* Free memory */
RB_REMOVE(&channels, ch, ch_link);
@ -625,6 +630,21 @@ channel_init ( void )
htsmsg_destroy(c);
}
/**
*
*/
void
channel_done ( void )
{
channel_t *ch;
pthread_mutex_lock(&global_lock);
while ((ch = RB_FIRST(&channels)) != NULL)
channel_delete(ch, 0);
pthread_mutex_unlock(&global_lock);
channel_tag_done();
}
/* ***
* Channel tags TODO
*/
@ -738,15 +758,17 @@ channel_tag_find(const char *id, int create)
*
*/
static void
channel_tag_destroy(channel_tag_t *ct)
channel_tag_destroy(channel_tag_t *ct, int delconf)
{
channel_tag_mapping_t *ctm;
channel_t *ch;
while((ctm = LIST_FIRST(&ct->ct_ctms)) != NULL) {
ch = ctm->ctm_channel;
channel_tag_mapping_destroy(ctm, CTM_DESTROY_UPDATE_CHANNEL);
channel_save(ch);
if (delconf) {
while((ctm = LIST_FIRST(&ct->ct_ctms)) != NULL) {
ch = ctm->ctm_channel;
channel_tag_mapping_destroy(ctm, CTM_DESTROY_UPDATE_CHANNEL);
channel_save(ch);
}
}
if(ct->ct_enabled && !ct->ct_internal)
@ -884,7 +906,7 @@ channel_tag_record_delete(void *opaque, const char *id)
if((ct = channel_tag_find(id, 0)) == NULL)
return -1;
channel_tag_destroy(ct);
channel_tag_destroy(ct, 1);
return 0;
}
@ -955,3 +977,15 @@ channel_tag_init ( void )
channeltags_dtable = dtable_create(&channel_tags_dtc, "channeltags", NULL);
dtable_load(channeltags_dtable);
}
static void
channel_tag_done ( void )
{
channel_tag_t *ct;
pthread_mutex_lock(&global_lock);
while ((ct = TAILQ_FIRST(&channel_tags)) != NULL)
channel_tag_destroy(ct, 0);
pthread_mutex_unlock(&global_lock);
dtable_delete("channeltags");
}

View file

@ -120,6 +120,7 @@ typedef struct channel_service_mapping {
extern const idclass_t channel_class;
void channel_init(void);
void channel_done(void);
channel_t *channel_create0
(channel_t *ch, const idclass_t *idc, const char *uuid, htsmsg_t *conf,
@ -127,7 +128,7 @@ channel_t *channel_create0
#define channel_create(u, c, n)\
channel_create0(calloc(1, sizeof(channel_t)), &channel_class, u, c, n)
void channel_delete(channel_t *ch);
void channel_delete(channel_t *ch, int delconf);
channel_t *channel_find_by_name(const char *name);
#define channel_find_by_uuid(u)\

View file

@ -33,6 +33,11 @@ void config_init ( void )
}
}
void config_done ( void )
{
htsmsg_destroy(config);
}
void config_save ( void )
{
hts_settings_save(config, "config");

View file

@ -24,6 +24,7 @@
#include "htsmsg.h"
void config_init ( void );
void config_done ( void );
void config_save ( void );
htsmsg_t *config_get_all ( void );

View file

@ -77,6 +77,7 @@ typedef enum {
LIST_HEAD(caid_list, caid);
void descrambler_init ( void );
void descrambler_done ( void );
void descrambler_service_start ( struct service *t );
const char *descrambler_caid2name(uint16_t caid);
uint16_t descrambler_name2caid(const char *str);

View file

@ -184,6 +184,8 @@ typedef struct capmt {
struct capmt_service_list capmt_services;
pthread_t capmt_tid;
/* from capmt configuration */
char *capmt_sockfile;
char *capmt_hostname;
@ -1113,7 +1115,6 @@ capmt_destroy(capmt_t *capmt)
static capmt_t *
capmt_entry_find(const char *id, int create)
{
pthread_t ptid;
char buf[20];
capmt_t *capmt;
static int tally;
@ -1142,7 +1143,7 @@ capmt_entry_find(const char *id, int create)
TAILQ_INSERT_TAIL(&capmts, capmt, capmt_link);
tvhthread_create(&ptid, NULL, capmt_thread, capmt, 1);
tvhthread_create(&capmt->capmt_tid, NULL, capmt_thread, capmt, 1);
return capmt;
}
@ -1280,3 +1281,19 @@ capmt_init(void)
dtable_load(dt);
}
void
capmt_done(void)
{
capmt_t *capmt, *n;
pthread_t tid;
for (capmt = TAILQ_FIRST(&capmts); capmt != NULL; capmt = n) {
n = TAILQ_NEXT(capmt, capmt_link);
pthread_mutex_lock(&global_lock);
tid = capmt->capmt_tid;
capmt_destroy(capmt);
pthread_mutex_unlock(&global_lock);
pthread_join(tid, NULL);
}
dtable_delete("capmt");
}

View file

@ -21,6 +21,8 @@
void capmt_init(void);
void capmt_done(void);
void capmt_service_start(struct service *t);
#endif /* CAPMT_H_ */

View file

@ -27,6 +27,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <openssl/des.h>
@ -184,9 +185,9 @@ typedef struct cwc_provider {
typedef struct cs_card_data {
LIST_ENTRY(cs_card_data) cs_card;
/* Card caid */
uint16_t cwc_caid;
uint16_t cwc_caid;
/* Card type */
card_type_t cwc_card_type;
@ -210,6 +211,8 @@ typedef struct cwc {
int cwc_retry_delay;
pthread_t cwc_tid;
pthread_cond_t cwc_cond;
pthread_mutex_t cwc_writer_mutex;
@ -465,8 +468,7 @@ cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid, int enq, uint1
int seq = atomic_add(&cwc->cwc_seq, 1);
memset(buf, 0, 12);
buf[0] = buf[1] = 0;
buf[2] = (seq >> 8) & 0xff;
buf[3] = seq & 0xff;
buf[4] = (sid >> 8) & 0xff;
@ -488,7 +490,7 @@ cwc_send_msg(cwc_t *cwc, const uint8_t *msg, size_t len, int sid, int enq, uint1
}
tvhtrace("cwc", "sending message sid %d len %"PRIsize_t" enq %d", sid, len, enq);
tvhlog_hexdump("cwc", msg, len);
tvhlog_hexdump("cwc", buf, len);
buf[0] = (len - 2) >> 8;
buf[1] = (len - 2) & 0xff;
@ -1194,6 +1196,7 @@ cwc_thread(void *aux)
cwc->cwc_hostname, cwc->cwc_port);
}
if(cwc->cwc_running == 0) continue;
if(attempts == 1) continue; // Retry immediately
d = 3;
@ -1224,6 +1227,7 @@ cwc_thread(void *aux)
free((void *)cwc->cwc_password);
free((void *)cwc->cwc_password_salted);
free((void *)cwc->cwc_username);
free((void *)cwc->cwc_comment);
free((void *)cwc->cwc_hostname);
free((void *)cwc->cwc_id);
free((void *)cwc->cwc_viaccess_emm.shared_emm);
@ -2066,7 +2070,6 @@ cwc_destroy(cwc_t *cwc)
static cwc_t *
cwc_entry_find(const char *id, int create)
{
pthread_t ptid;
char buf[20];
cwc_t *cwc;
static int tally;
@ -2094,7 +2097,7 @@ cwc_entry_find(const char *id, int create)
cwc->cwc_running = 1;
TAILQ_INSERT_TAIL(&cwcs, cwc, cwc_link);
tvhthread_create(&ptid, NULL, cwc_thread, cwc, 1);
tvhthread_create(&cwc->cwc_tid, NULL, cwc_thread, cwc, 0);
return cwc;
}
@ -2337,6 +2340,29 @@ cwc_init(void)
}
/**
*
*/
void
cwc_done(void)
{
cwc_t *cwc;
pthread_t tid;
dtable_delete("cwc");
pthread_mutex_lock(&cwc_mutex);
while ((cwc = TAILQ_FIRST(&cwcs)) != NULL) {
tid = cwc->cwc_tid;
cwc_destroy(cwc);
pthread_mutex_unlock(&cwc_mutex);
pthread_kill(tid, SIGTERM);
pthread_join(tid, NULL);
pthread_mutex_lock(&cwc_mutex);
}
pthread_mutex_unlock(&cwc_mutex);
}
#include <openssl/md5.h>
/*

View file

@ -21,6 +21,8 @@
void cwc_init(void);
void cwc_done(void);
void cwc_service_start(struct service *t);
void cwc_emm(uint8_t *data, int len, uint16_t caid, void *ca_update_id);

View file

@ -115,6 +115,13 @@ descrambler_init ( void )
#endif
}
void
descrambler_done ( void )
{
capmt_done();
cwc_done();
}
void
descrambler_service_start ( service_t *t )
{

View file

@ -63,6 +63,23 @@ dtable_create(const dtable_class_t *dtc, const char *name, void *opaque)
return dt;
}
/**
*
*/
void
dtable_delete(const char *name)
{
dtable_t *dt = dtable_find(name);
if (dt) {
pthread_mutex_lock(&global_lock);
LIST_REMOVE(dt, dt_link);
pthread_mutex_unlock(&global_lock);
free(dt->dt_tablename);
free(dt);
}
}
/**
*
*/

View file

@ -58,6 +58,8 @@ typedef struct dtable {
dtable_t *dtable_create(const dtable_class_t *dtc, const char *name,
void *opaque);
void dtable_delete(const char *name);
int dtable_load(dtable_t *dt);
dtable_t *dtable_find(const char *name);

View file

@ -296,8 +296,12 @@ dvr_entry_t *dvr_entry_update
void dvr_init(void);
void dvr_done(void);
void dvr_autorec_init(void);
void dvr_autorec_done(void);
void dvr_autorec_update(void);
void dvr_destroy_by_channel(channel_t *ch);
@ -384,7 +388,7 @@ void dvr_autorec_check_season(epg_season_t *s);
void dvr_autorec_check_serieslink(epg_serieslink_t *s);
void autorec_destroy_by_channel(channel_t *ch);
void autorec_destroy_by_channel(channel_t *ch, int delconf);
dvr_autorec_entry_t *autorec_entry_find(const char *id, int create);
@ -399,6 +403,7 @@ const char *dvr_val2pri(dvr_prio_t v);
* Inotify support
*/
void dvr_inotify_init ( void );
void dvr_inotify_done ( void );
void dvr_inotify_add ( dvr_entry_t *de );
void dvr_inotify_del ( dvr_entry_t *de );

View file

@ -480,6 +480,20 @@ dvr_autorec_init(void)
dvr_autorec_in_init = 0;
}
void
dvr_autorec_done(void)
{
dvr_autorec_entry_t *dae;
pthread_mutex_lock(&global_lock);
while ((dae = TAILQ_FIRST(&autorec_entries)) != NULL) {
TAILQ_REMOVE(&autorec_entries, dae, dae_link);
free(dae);
}
pthread_mutex_unlock(&global_lock);
dtable_delete("autorec");
}
void
dvr_autorec_update(void)
{
@ -638,13 +652,14 @@ dvr_autorec_changed(dvr_autorec_entry_t *dae, int purge)
*
*/
void
autorec_destroy_by_channel(channel_t *ch)
autorec_destroy_by_channel(channel_t *ch, int delconf)
{
dvr_autorec_entry_t *dae;
htsmsg_t *m;
while((dae = LIST_FIRST(&ch->ch_autorecs)) != NULL) {
dtable_record_erase(autorec_dt, dae->dae_id);
if (delconf)
dtable_record_erase(autorec_dt, dae->dae_id);
autorec_entry_destroy(dae);
}

View file

@ -490,6 +490,7 @@ dvr_entry_dec_ref(dvr_entry_t *de)
if(de->de_autorec != NULL)
LIST_REMOVE(de, de_autorec_link);
free(de->de_filename);
free(de->de_config_name);
free(de->de_creator);
if (de->de_title) lang_str_destroy(de->de_title);
@ -506,9 +507,10 @@ dvr_entry_dec_ref(dvr_entry_t *de)
*
*/
static void
dvr_entry_remove(dvr_entry_t *de)
dvr_entry_remove(dvr_entry_t *de, int delconf)
{
hts_settings_remove("dvr/log/%d", de->de_id);
if (delconf)
hts_settings_remove("dvr/log/%d", de->de_id);
htsp_dvr_entry_delete(de);
@ -523,6 +525,7 @@ dvr_entry_remove(dvr_entry_t *de)
LIST_REMOVE(de, de_global_link);
de->de_channel = NULL;
free(de->de_channel_name);
de->de_channel_name = NULL;
dvrdb_changed();
@ -729,7 +732,7 @@ static void
dvr_timer_expire(void *aux)
{
dvr_entry_t *de = aux;
dvr_entry_remove(de);
dvr_entry_remove(de, 1);
}
@ -857,7 +860,7 @@ dvr_event_replaced(epg_broadcast_t *e, epg_broadcast_t *new_e)
/* If this was craeted by autorec - just remove it, it'll get recreated */
if (de->de_autorec) {
dvr_entry_remove(de);
dvr_entry_remove(de, 1);
/* Find match */
} else {
@ -1025,7 +1028,7 @@ dvr_entry_cancel(dvr_entry_t *de)
{
switch(de->de_sched_state) {
case DVR_SCHEDULED:
dvr_entry_remove(de);
dvr_entry_remove(de, 1);
return NULL;
case DVR_RECORDING:
@ -1034,11 +1037,11 @@ dvr_entry_cancel(dvr_entry_t *de)
return de;
case DVR_COMPLETED:
dvr_entry_remove(de);
dvr_entry_remove(de, 1);
return NULL;
case DVR_MISSED_TIME:
dvr_entry_remove(de);
dvr_entry_remove(de, 1);
return NULL;
default:
@ -1208,6 +1211,31 @@ dvr_init(void)
dvr_autorec_update();
}
/**
*
*/
void
dvr_done(void)
{
dvr_config_t *cfg;
dvr_entry_t *de;
#if ENABLE_INOTIFY
dvr_inotify_done();
#endif
pthread_mutex_lock(&global_lock);
while ((cfg = LIST_FIRST(&dvrconfigs)) != NULL) {
LIST_REMOVE(cfg, config_link);
free(cfg->dvr_storage);
free(cfg->dvr_config_name);
free(cfg);
}
while ((de = LIST_FIRST(&dvrentries)) != NULL)
dvr_entry_remove(de, 0);
pthread_mutex_unlock(&global_lock);
dvr_autorec_done();
}
/**
* find a dvr config by name, return NULL if not found
*/
@ -1306,6 +1334,7 @@ dvr_config_delete(const char *name)
cfg->dvr_config_name);
hts_settings_remove("dvr/config%s", cfg->dvr_config_name);
LIST_REMOVE(cfg, config_link);
free(cfg->dvr_config_name);
free(cfg);
dvrconfig_changed();
@ -1647,7 +1676,7 @@ dvr_entry_delete(dvr_entry_t *de)
}
}
dvr_entry_remove(de);
dvr_entry_remove(de, 1);
}
/**
@ -1658,7 +1687,7 @@ dvr_entry_cancel_delete(dvr_entry_t *de)
{
switch(de->de_sched_state) {
case DVR_SCHEDULED:
dvr_entry_remove(de);
dvr_entry_remove(de, 1);
break;
case DVR_RECORDING:
@ -1669,7 +1698,7 @@ dvr_entry_cancel_delete(dvr_entry_t *de)
break;
case DVR_MISSED_TIME:
dvr_entry_remove(de);
dvr_entry_remove(de, 1);
break;
default:

View file

@ -20,6 +20,8 @@
#include <unistd.h>
#include <assert.h>
#include <poll.h>
#include <signal.h>
#include <pthread.h>
#include <sys/inotify.h>
#include <sys/stat.h>
@ -45,6 +47,8 @@ typedef struct dvr_inotify_entry
struct dvr_entry_list entries;
} dvr_inotify_entry_t;
static SKEL_DECLARE(dvr_inotify_entry_skel, dvr_inotify_entry_t);
static void* _dvr_inotify_thread ( void *p );
static int _str_cmp ( void *a, void *b )
@ -55,10 +59,10 @@ static int _str_cmp ( void *a, void *b )
/**
* Initialise threads
*/
pthread_t dvr_inotify_tid;
void dvr_inotify_init ( void )
{
pthread_t tid;
_inot_fd = inotify_init();
if (_inot_fd == -1) {
tvhlog(LOG_ERR, "dvr", "failed to initialise inotify (err=%s)",
@ -66,7 +70,20 @@ void dvr_inotify_init ( void )
return;
}
tvhthread_create(&tid, NULL, _dvr_inotify_thread, NULL, 1);
tvhthread_create(&dvr_inotify_tid, NULL, _dvr_inotify_thread, NULL, 0);
}
/**
*
*/
void dvr_inotify_done ( void )
{
int fd = _inot_fd;
_inot_fd = -1;
close(fd);
pthread_kill(dvr_inotify_tid, SIGTERM);
pthread_join(dvr_inotify_tid, NULL);
SKEL_FREE(dvr_inotify_entry_skel);
}
/**
@ -74,7 +91,6 @@ void dvr_inotify_init ( void )
*/
void dvr_inotify_add ( dvr_entry_t *de )
{
static dvr_inotify_entry_t *skel = NULL;
dvr_inotify_entry_t *e;
char *path;
struct stat st;
@ -87,17 +103,16 @@ void dvr_inotify_add ( dvr_entry_t *de )
path = strdup(de->de_filename);
if (!skel)
skel = calloc(1, sizeof(dvr_inotify_entry_t));
skel->path = dirname(path);
SKEL_ALLOC(dvr_inotify_entry_skel);
dvr_inotify_entry_skel->path = dirname(path);
if (stat(skel->path, &st))
if (stat(dvr_inotify_entry_skel->path, &st))
return;
e = RB_INSERT_SORTED(&_inot_tree, skel, link, _str_cmp);
e = RB_INSERT_SORTED(&_inot_tree, dvr_inotify_entry_skel, link, _str_cmp);
if (!e) {
e = skel;
skel = NULL;
e = dvr_inotify_entry_skel;
SKEL_USED(dvr_inotify_entry_skel);
e->path = strdup(e->path);
e->fd = inotify_add_watch(_inot_fd, e->path, EVENT_MASK);
if (e->fd == -1) {
@ -258,6 +273,8 @@ void* _dvr_inotify_thread ( void *p )
from = NULL;
i = 0;
len = read(_inot_fd, buf, EVENT_BUF_LEN);
if (_inot_fd < 0)
break;
/* Process */
pthread_mutex_lock(&global_lock);

View file

@ -2314,3 +2314,18 @@ char *epg_hash ( const char *t, const char *s, const char *d )
if ( t ) return md5sum(t);
return NULL;
}
void epg_skel_done(void)
{
epg_object_t **skel;
epg_broadcast_t **broad;
skel = _epg_brand_skel();
free(*skel); *skel = NULL;
skel = _epg_season_skel();
free(*skel); *skel = NULL;
skel = _epg_episode_skel();
free(*skel); *skel = NULL;
broad = _epg_broadcast_skel();
free(*broad); *broad = NULL;
}

View file

@ -556,7 +556,10 @@ void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
* ***********************************************************************/
void epg_init (void);
void epg_save (void*);
void epg_done (void);
void epg_skel_done (void);
void epg_save (void);
void epg_save_callback (void *p);
void epg_updated (void);
/* ************************************************************************

View file

@ -100,40 +100,40 @@ static void _epgdb_v1_process ( htsmsg_t *c, epggrab_stats_t *stats )
/*
* Process v2 data
*/
static void _epgdb_v2_process ( htsmsg_t *m, epggrab_stats_t *stats )
static void
_epgdb_v2_process( char **sect, htsmsg_t *m, epggrab_stats_t *stats )
{
int save = 0;
const char *s;
static char *sect;
/* New section */
if ( (s = htsmsg_get_str(m, "__section__")) ) {
if (sect) free(sect);
sect = strdup(s);
if (*sect) free(*sect);
*sect = strdup(s);
/* Brand */
} else if ( !strcmp(sect, "brands") ) {
} else if ( !strcmp(*sect, "brands") ) {
if (epg_brand_deserialize(m, 1, &save)) stats->brands.total++;
/* Season */
} else if ( !strcmp(sect, "seasons") ) {
} else if ( !strcmp(*sect, "seasons") ) {
if (epg_season_deserialize(m, 1, &save)) stats->seasons.total++;
/* Episode */
} else if ( !strcmp(sect, "episodes") ) {
} else if ( !strcmp(*sect, "episodes") ) {
if (epg_episode_deserialize(m, 1, &save)) stats->episodes.total++;
/* Series link */
} else if ( !strcmp(sect, "serieslinks") ) {
} else if ( !strcmp(*sect, "serieslinks") ) {
if (epg_serieslink_deserialize(m, 1, &save)) stats->seasons.total++;
/* Broadcasts */
} else if ( !strcmp(sect, "broadcasts") ) {
} else if ( !strcmp(*sect, "broadcasts") ) {
if (epg_broadcast_deserialize(m, 1, &save)) stats->broadcasts.total++;
/* Unknown */
} else {
tvhlog(LOG_DEBUG, "epgdb", "malformed database section [%s]", sect);
tvhlog(LOG_DEBUG, "epgdb", "malformed database section [%s]", *sect);
//htsmsg_print(m);
}
}
@ -149,6 +149,7 @@ void epg_init ( void )
uint8_t *mem, *rp;
epggrab_stats_t stats;
int ver = EPG_DB_VERSION;
char *sect = NULL;
/* Find the right file (and version) */
while (fd < 0 && ver > 0) {
@ -207,7 +208,7 @@ void epg_init ( void )
/* Process */
switch (ver) {
case 2:
_epgdb_v2_process(m, &stats);
_epgdb_v2_process(&sect, m, &stats);
break;
default:
break;
@ -217,6 +218,8 @@ void epg_init ( void )
htsmsg_destroy(m);
}
free(sect);
/* Stats */
tvhlog(LOG_INFO, "epgdb", "loaded v%d", ver);
tvhlog(LOG_INFO, "epgdb", " channels %d", stats.channels.total);
@ -230,6 +233,17 @@ void epg_init ( void )
close(fd);
}
void epg_done ( void )
{
channel_t *ch;
pthread_mutex_lock(&global_lock);
CHANNEL_FOREACH(ch)
epg_channel_unlink(ch);
epg_skel_done();
pthread_mutex_unlock(&global_lock);
}
/* **************************************************************************
* Save
* *************************************************************************/
@ -264,7 +278,12 @@ static int _epg_write_sect ( int fd, const char *sect )
return _epg_write(fd, m);
}
void epg_save ( void *p )
void epg_save_callback ( void *p )
{
epg_save();
}
void epg_save ( void )
{
int fd;
epg_object_t *eo;
@ -274,7 +293,7 @@ void epg_save ( void *p )
extern gtimer_t epggrab_save_timer;
if (epggrab_epgdb_periodicsave)
gtimer_arm(&epggrab_save_timer, epg_save, NULL, epggrab_epgdb_periodicsave);
gtimer_arm(&epggrab_save_timer, epg_save_callback, NULL, epggrab_epgdb_periodicsave);
fd = hts_settings_open_file(1, "epgdb.v%d", EPG_DB_VERSION);

View file

@ -41,6 +41,7 @@
static int epggrab_confver;
pthread_mutex_t epggrab_mutex;
static pthread_cond_t epggrab_cond;
int epggrab_running;
/* Config */
uint32_t epggrab_interval;
@ -96,7 +97,7 @@ static void* _epggrab_internal_thread ( void* p )
/* Check for config change */
pthread_mutex_lock(&epggrab_mutex);
while ( confver == epggrab_confver ) {
while ( epggrab_running && confver == epggrab_confver ) {
if (epggrab_module) {
err = pthread_cond_timedwait(&epggrab_cond, &epggrab_mutex, &ts);
} else {
@ -109,6 +110,9 @@ static void* _epggrab_internal_thread ( void* p )
ts.tv_sec += epggrab_interval;
pthread_mutex_unlock(&epggrab_mutex);
if ( !epggrab_running)
break;
/* Run grabber */
if (mod) _epggrab_module_grab(mod);
}
@ -143,7 +147,7 @@ static void _epggrab_load ( void )
htsmsg_get_u32(m, "channel_reicon", &epggrab_channel_reicon);
htsmsg_get_u32(m, "epgdb_periodicsave", &epggrab_epgdb_periodicsave);
if (epggrab_epgdb_periodicsave)
gtimer_arm(&epggrab_save_timer, epg_save, NULL,
gtimer_arm(&epggrab_save_timer, epg_save_callback, NULL,
epggrab_epgdb_periodicsave);
if (!htsmsg_get_u32(m, old ? "grab-interval" : "interval",
&epggrab_interval)) {
@ -319,7 +323,7 @@ int epggrab_set_periodicsave ( uint32_t e )
if (!e)
gtimer_disarm(&epggrab_save_timer);
else
epg_save(NULL); // will arm the timer
epg_save(); // will arm the timer
pthread_mutex_unlock(&global_lock);
save = 1;
}
@ -368,6 +372,8 @@ void epggrab_resched ( void )
/*
* Initialise
*/
pthread_t epggrab_tid;
void epggrab_init ( void )
{
/* Defaults */
@ -396,11 +402,33 @@ void epggrab_init ( void )
_epggrab_load();
/* Start internal grab thread */
pthread_t tid;
pthread_attr_t tattr;
pthread_attr_init(&tattr);
pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
tvhthread_create(&tid, &tattr, _epggrab_internal_thread, NULL, 1);
pthread_attr_destroy(&tattr);
epggrab_running = 1;
tvhthread_create(&epggrab_tid, NULL, _epggrab_internal_thread, NULL, 0);
}
/*
* Cleanup
*/
void epggrab_done ( void )
{
epggrab_module_t *mod;
epggrab_running = 0;
pthread_cond_signal(&epggrab_cond);
pthread_join(epggrab_tid, NULL);
pthread_mutex_lock(&global_lock);
while ((mod = LIST_FIRST(&epggrab_modules)) != NULL) {
LIST_REMOVE(mod, link);
if (mod->type == EPGGRAB_OTA && ((epggrab_module_ota_t *)mod)->done)
((epggrab_module_ota_t *)mod)->done((epggrab_module_ota_t *)mod);
if (mod->type == EPGGRAB_INT || mod->type == EPGGRAB_EXT)
free((void *)((epggrab_module_int_t *)mod)->path);
free((void *)mod->id);
free((void *)mod->name);
free(mod);
}
pthread_mutex_unlock(&global_lock);
epggrab_ota_done_();
opentv_done();
}

View file

@ -221,6 +221,7 @@ struct epggrab_module_ota
/* Transponder tuning */
void (*start) ( epggrab_module_ota_t *m, struct mpegts_mux *mm );
void (*done) ( epggrab_module_ota_t *m );
};
/*
@ -238,6 +239,7 @@ htsmsg_t* epggrab_module_list ( void );
*/
extern epggrab_module_list_t epggrab_modules;
extern pthread_mutex_t epggrab_mutex;
extern int epggrab_running;
extern uint32_t epggrab_interval;
extern epggrab_module_int_t* epggrab_module;
extern uint32_t epggrab_channel_rename;
@ -262,8 +264,10 @@ int epggrab_enable_module_by_id ( const char *id, uint8_t e );
* Load/Save
*/
void epggrab_init ( void );
void epggrab_done ( void );
void epggrab_save ( void );
void epggrab_ota_init ( void );
void epggrab_ota_done_ ( void );
/* **************************************************************************
* Global Functions

View file

@ -345,7 +345,7 @@ static void *_epggrab_socket_thread ( void *p )
epggrab_module_ext_t *mod = (epggrab_module_ext_t*)p;
tvhlog(LOG_INFO, mod->id, "external socket enabled");
while ( mod->enabled && mod->sock ) {
while ( epggrab_running && mod->enabled && mod->sock ) {
tvhlog(LOG_DEBUG, mod->id, "waiting for connection");
s = accept(mod->sock, NULL, NULL);
if (s <= 0) continue;
@ -452,6 +452,7 @@ epggrab_module_ota_t *epggrab_module_ota_create
void (*start) (epggrab_module_ota_t*m,
struct mpegts_mux *dm),
int (*enable) (void *m, uint8_t e ),
void (*done) (epggrab_module_ota_t *m),
epggrab_channel_tree_t *channels )
{
if (!skel) skel = calloc(1, sizeof(epggrab_module_ota_t));
@ -463,6 +464,7 @@ epggrab_module_ota_t *epggrab_module_ota_create
skel->type = EPGGRAB_OTA;
skel->enable = enable;
skel->start = start;
skel->done = done;
//TAILQ_INIT(&skel->muxes);
return skel;

View file

@ -555,7 +555,7 @@ _eit_callback
uint16_t onid, tsid, sid;
uint32_t extraid;
mpegts_service_t *svc;
mpegts_mux_t *mm = mt->mt_mux;;
mpegts_mux_t *mm = mt->mt_mux;
epggrab_module_t *mod = mt->mt_opaque;
epggrab_ota_mux_t *ota = NULL;
mpegts_table_state_t *st;
@ -680,11 +680,11 @@ static void _eit_start
void eit_init ( void )
{
epggrab_module_ota_create(NULL, "eit", "EIT: DVB Grabber", 1,
_eit_start, NULL, NULL);
_eit_start, NULL, NULL, NULL);
epggrab_module_ota_create(NULL, "uk_freesat", "UK: Freesat", 5,
_eit_start, NULL, NULL);
_eit_start, NULL, NULL, NULL);
epggrab_module_ota_create(NULL, "uk_freeview", "UK: Freeview", 5,
_eit_start, NULL, NULL);
_eit_start, NULL, NULL, NULL);
epggrab_module_ota_create(NULL, "viasat_baltic", "VIASAT: Baltic", 5,
_eit_start, NULL, NULL);
_eit_start, NULL, NULL, NULL);
}

View file

@ -686,6 +686,14 @@ static void _opentv_dict_load ( htsmsg_t *m )
htsmsg_destroy(m);
}
static void _opentv_done( epggrab_module_ota_t *m )
{
opentv_module_t *mod = (opentv_module_t *)m;
free(mod->channel);
free(mod->title);
free(mod->summary);
}
static int _opentv_prov_load_one ( const char *id, htsmsg_t *m )
{
char ibuf[100], nbuf[1000];
@ -726,7 +734,7 @@ static int _opentv_prov_load_one ( const char *id, htsmsg_t *m )
epggrab_module_ota_create(calloc(1, sizeof(opentv_module_t)),
ibuf, nbuf, 2,
_opentv_start, NULL,
NULL);
_opentv_done, NULL);
/* Add provider details */
mod->dict = dict;
@ -785,6 +793,24 @@ void opentv_init ( void )
tvhlog(LOG_DEBUG, "opentv", "providers loaded");
}
void opentv_done ( void )
{
opentv_dict_t *dict;
opentv_genre_t *genre;
while ((dict = RB_FIRST(&_opentv_dicts)) != NULL) {
RB_REMOVE(&_opentv_dicts, dict, h_link);
huffman_tree_destroy(dict->codes);
free(dict->id);
free(dict);
}
while ((genre = RB_FIRST(&_opentv_genres)) != NULL) {
RB_REMOVE(&_opentv_genres, genre, h_link);
free(genre->id);
free(genre);
}
}
void opentv_load ( void )
{
// TODO: do we want to keep a list of channels stored?

View file

@ -37,6 +37,8 @@ LIST_HEAD(,epggrab_ota_mux) epggrab_ota_active;
gtimer_t epggrab_ota_pending_timer;
gtimer_t epggrab_ota_active_timer;
SKEL_DECLARE(epggrab_ota_mux_skel, epggrab_ota_mux_t);
static void epggrab_ota_active_timer_cb ( void *p );
static void epggrab_ota_pending_timer_cb ( void *p );
@ -191,23 +193,21 @@ epggrab_ota_register
int interval, int timeout )
{
int save = 0;
static epggrab_ota_mux_t *skel = NULL;
epggrab_ota_map_t *map;
epggrab_ota_mux_t *ota;
/* Find mux entry */
const char *uuid = idnode_uuid_as_str(&mm->mm_id);
if (!skel)
skel = calloc(1, sizeof(epggrab_ota_mux_t));
skel->om_mux_uuid = (char*)uuid;
SKEL_ALLOC(epggrab_ota_mux_skel);
epggrab_ota_mux_skel->om_mux_uuid = (char*)uuid;
ota = RB_INSERT_SORTED(&epggrab_ota_all, skel, om_global_link, om_id_cmp);
ota = RB_INSERT_SORTED(&epggrab_ota_all, epggrab_ota_mux_skel, om_global_link, om_id_cmp);
if (!ota) {
char buf[256];
mm->mm_display_name(mm, buf, sizeof(buf));
tvhinfo(mod->id, "registering mux %s", buf);
ota = skel;
skel = NULL;
ota = epggrab_ota_mux_skel;
SKEL_USED(epggrab_ota_mux_skel);
ota->om_mux_uuid = strdup(uuid);
ota->om_when = dispatch_clock + epggrab_ota_timeout(ota);
ota->om_active = 1;
@ -375,6 +375,7 @@ epggrab_ota_save ( epggrab_ota_mux_t *ota )
}
htsmsg_add_msg(c, "modules", l);
hts_settings_save(c, "epggrab/otamux/%s", ota->om_mux_uuid);
htsmsg_destroy(c);
}
static void
@ -457,6 +458,34 @@ epggrab_ota_init ( void )
NULL, 0);
}
static void
epggrab_ota_free ( epggrab_ota_mux_t *ota )
{
epggrab_ota_map_t *map;
LIST_REMOVE(ota, om_q_link);
while ((map = LIST_FIRST(&ota->om_modules)) != NULL) {
LIST_REMOVE(map, om_link);
free(map);
}
free(ota->om_mux_uuid);
free(ota);
}
void
epggrab_ota_done_ ( void )
{
epggrab_ota_mux_t *ota;
pthread_mutex_lock(&global_lock);
while ((ota = LIST_FIRST(&epggrab_ota_active)) != NULL)
epggrab_ota_free(ota);
while ((ota = LIST_FIRST(&epggrab_ota_pending)) != NULL)
epggrab_ota_free(ota);
pthread_mutex_unlock(&global_lock);
SKEL_FREE(epggrab_ota_mux_skel);
}
/******************************************************************************
* Editor Configuration
*

View file

@ -91,6 +91,7 @@ epggrab_module_ota_t *epggrab_module_ota_create
void (*start) (epggrab_module_ota_t*m,
struct mpegts_mux *mm),
int (*enable) (void *m, uint8_t e ),
void (*done) (epggrab_module_ota_t*m),
epggrab_channel_tree_t *channels );
/* **************************************************************************
@ -162,6 +163,7 @@ void eit_load ( void );
/* OpenTV module */
void opentv_init ( void );
void opentv_done ( void );
void opentv_load ( void );
/* PyEPG module */

View file

@ -24,6 +24,7 @@
#if ENABLE_INOTIFY
#include <signal.h>
#include <sys/inotify.h>
#include <sys/stat.h>
@ -56,6 +57,8 @@ fsmonitor_thread ( void* p )
/* Wait for event */
c = read(fsmonitor_fd, buf, sizeof(buf));
if (fsmonitor_fd < 0)
break;
/* Process */
pthread_mutex_lock(&global_lock);
@ -94,14 +97,27 @@ fsmonitor_thread ( void* p )
/*
* Start the fsmonitor subsystem
*/
pthread_t fsmonitor_tid;
void
fsmonitor_init ( void )
{
pthread_t tid;
/* Intialise inotify */
fsmonitor_fd = inotify_init();
tvhthread_create0(&tid, NULL, fsmonitor_thread, NULL, "fsmonitor", 1);
tvhthread_create0(&fsmonitor_tid, NULL, fsmonitor_thread, NULL, "fsmonitor", 0);
}
/*
* Stop the fsmonitor subsystem
*/
void
fsmonitor_done ( void )
{
int fd = fsmonitor_fd;
fsmonitor_fd = -1;
close(fd);
pthread_kill(fsmonitor_tid, SIGTERM);
pthread_join(fsmonitor_tid, NULL);
}
/*
@ -111,13 +127,13 @@ int
fsmonitor_add ( const char *path, fsmonitor_t *fsm )
{
int mask;
static fsmonitor_path_t *skel = NULL;
fsmonitor_path_t *skel;
fsmonitor_path_t *fmp;
fsmonitor_link_t *fml;
lock_assert(&global_lock);
if (!skel) skel = calloc(1, sizeof(fsmonitor_path_t));
skel = calloc(1, sizeof(fsmonitor_path_t));
skel->fmp_path = (char*)path;
/* Build mask */
@ -127,21 +143,22 @@ fsmonitor_add ( const char *path, fsmonitor_t *fsm )
fmp = RB_INSERT_SORTED(&fsmonitor_paths, skel, fmp_link, fmp_cmp);
if (!fmp) {
fmp = skel;
fmp->fmp_fd
= inotify_add_watch(fsmonitor_fd, path, mask);
fmp->fmp_fd = inotify_add_watch(fsmonitor_fd, path, mask);
/* Failed */
if (fmp->fmp_fd <= 0) {
RB_REMOVE(&fsmonitor_paths, skel, fmp_link);
RB_REMOVE(&fsmonitor_paths, fmp, fmp_link);
free(fmp);
tvhdebug("fsmonitor", "failed to add %s (exists?)", path);
printf("ERROR: failed to add %s\n", path);
return -1;
}
/* Setup */
skel = NULL;
fmp->fmp_path = strdup(path);
tvhdebug("fsmonitor", "watch %s", fmp->fmp_path);
} else {
free(skel);
}
/* Check doesn't exist */
@ -165,17 +182,16 @@ fsmonitor_add ( const char *path, fsmonitor_t *fsm )
void
fsmonitor_del ( const char *path, fsmonitor_t *fsm )
{
static fsmonitor_path_t *skel = NULL;
static fsmonitor_path_t skel;
fsmonitor_path_t *fmp;
fsmonitor_link_t *fml;
lock_assert(&global_lock);
if (!skel) skel = calloc(1, sizeof(fsmonitor_path_t));
skel->fmp_path = (char*)path;
skel.fmp_path = (char*)path;
/* Find path */
fmp = RB_FIND(&fsmonitor_paths, skel, fmp_link, fmp_cmp);
fmp = RB_FIND(&fsmonitor_paths, &skel, fmp_link, fmp_cmp);
if (fmp) {
/* Find link */
@ -191,7 +207,7 @@ fsmonitor_del ( const char *path, fsmonitor_t *fsm )
}
/* Remove path */
if (!LIST_FIRST(&fmp->fmp_monitors)) {
if (LIST_EMPTY(&fmp->fmp_monitors)) {
tvhdebug("fsmonitor", "unwatch %s", fmp->fmp_path);
RB_REMOVE(&fsmonitor_paths, fmp, fmp_link);
inotify_rm_watch(fsmonitor_fd, fmp->fmp_fd);

View file

@ -47,6 +47,7 @@ struct fsmonitor {
};
void fsmonitor_init ( void );
void fsmonitor_done ( void );
int fsmonitor_add ( const char *path, fsmonitor_t *fsm );
void fsmonitor_del ( const char *path, fsmonitor_t *fsm );

View file

@ -47,6 +47,7 @@
#include <stdarg.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
@ -1986,7 +1987,7 @@ htsp_read_loop(htsp_connection_t *htsp)
/* Session main loop */
while(1) {
while(tvheadend_running) {
readmsg:
if((r = htsp_read_message(htsp, &m, 0)) != 0)
return r;
@ -2036,6 +2037,7 @@ readmsg:
htsmsg_destroy(m);
}
return 0;
}
/**
@ -2052,7 +2054,7 @@ htsp_write_scheduler(void *aux)
pthread_mutex_lock(&htsp->htsp_out_mutex);
while(1) {
while(tvheadend_running) {
if((hmq = TAILQ_FIRST(&htsp->htsp_active_output_queues)) == NULL) {
/* No active queues at all */
@ -2213,6 +2215,14 @@ htsp_server_status ( void *opaque, htsmsg_t *m )
htsmsg_add_str(m, "user", htsp->htsp_username);
}
/*
* Cancel callback
*/
static void
htsp_server_cancel ( void *opaque )
{
}
/**
* Fire up HTSP server
*/
@ -2224,12 +2234,25 @@ htsp_init(const char *bindaddr)
.start = htsp_serve,
.stop = NULL,
.status = htsp_server_status,
.cancel = htsp_server_cancel
};
htsp_server = tcp_server_create(bindaddr, tvheadend_htsp_port, &ops, NULL);
if(tvheadend_htsp_port_extra)
htsp_server_2 = tcp_server_create(bindaddr, tvheadend_htsp_port_extra, &ops, NULL);
}
/**
* Fire down HTSP server
*/
void
htsp_done(void)
{
if (htsp_server_2)
tcp_server_delete(htsp_server_2);
if (htsp_server)
tcp_server_delete(htsp_server);
}
/* **************************************************************************
* Asynchronous updates
* *************************************************************************/

View file

@ -23,6 +23,7 @@
#include "dvr/dvr.h"
void htsp_init(const char *bindaddr);
void htsp_done(void);
void htsp_channel_update_nownext(channel_t *ch);

View file

@ -25,6 +25,7 @@
#include <stdarg.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
@ -789,7 +790,7 @@ http_serve(int fd, void **opaque, struct sockaddr_storage *peer,
{
htsbuf_queue_t spill;
http_connection_t hc;
// Note: global_lock held on entry */
pthread_mutex_unlock(&global_lock);
memset(&hc, 0, sizeof(http_connection_t));
@ -845,3 +846,18 @@ http_server_init(const char *bindaddr)
};
http_server = tcp_server_create(bindaddr, tvheadend_webui_port, &ops, NULL);
}
void
http_server_done(void)
{
http_path_t *hp;
pthread_mutex_lock(&global_lock);
while ((hp = LIST_FIRST(&http_paths)) != NULL) {
LIST_REMOVE(hp, hp_link);
free((void *)hp->hp_path);
free(hp);
}
pthread_mutex_unlock(&global_lock);
tcp_server_delete(http_server);
}

View file

@ -136,6 +136,7 @@ http_path_t *http_path_add(const char *path, void *opaque,
http_callback_t *callback, uint32_t accessmask);
void http_server_init(const char *bindaddr);
void http_server_done(void);
int http_access_verify(http_connection_t *hc, int mask);
@ -148,6 +149,7 @@ typedef size_t (http_client_data_cb) (void *p, void *buf, size_t len);
typedef void (http_client_fail_cb) (void *p);
void http_client_init ( void );
void http_client_done ( void );
http_client_t*
http_connect ( const url_t *url,
http_client_conn_cb conn_cb,

View file

@ -30,6 +30,7 @@
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
/*
@ -141,7 +142,7 @@ http_thread ( void *p )
tvhpoll_event_t ev;
http_client_t *hc;
while (1) {
while (tvheadend_running) {
n = tvhpoll_wait(http_poll, &ev, 1, -1);
if (n < 0) {
tvherror("http_client", "tvhpoll_wait() error");
@ -217,11 +218,11 @@ http_close ( http_client_t *hc )
/*
* Initialise subsystem
*/
pthread_t http_client_tid;
void
http_client_init ( void )
{
pthread_t tid;
/* Setup list */
pthread_mutex_init(&http_lock, NULL);
TAILQ_INIT(&http_clients);
@ -235,7 +236,17 @@ http_client_init ( void )
http_poll = tvhpoll_create(10);
/* Setup thread */
tvhthread_create(&tid, NULL, http_thread, NULL, 1);
tvhthread_create(&http_client_tid, NULL, http_thread, NULL, 0);
}
void
http_client_done ( void )
{
pthread_kill(http_client_tid, SIGTERM);
pthread_join(http_client_tid, NULL);
tvhpoll_destroy(http_poll);
curl_multi_cleanup(http_curlm);
curl_global_cleanup();
}
#else /* ENABLE_CURL */
@ -245,4 +256,9 @@ http_client_init ( void )
{
}
void
http_client_done ( void )
{
}
#endif /* ENABLE_CURL */

View file

@ -43,6 +43,8 @@ static pthread_mutex_t idnode_mutex;
static htsmsg_t *idnode_queue;
static void* idnode_thread(void* p);
SKEL_DECLARE(idclasses_skel, idclass_link_t);
static void
idclass_register(const idclass_t *idc);
@ -120,11 +122,11 @@ in_cmp(const idnode_t *a, const idnode_t *b)
/**
*
*/
pthread_t idnode_tid;
void
idnode_init(void)
{
pthread_t tid;
randfd = open("/dev/urandom", O_RDONLY);
if(randfd == -1)
exit(1);
@ -132,7 +134,25 @@ idnode_init(void)
idnode_queue = NULL;
pthread_mutex_init(&idnode_mutex, NULL);
pthread_cond_init(&idnode_cond, NULL);
tvhthread_create(&tid, NULL, idnode_thread, NULL, 1);
tvhthread_create(&idnode_tid, NULL, idnode_thread, NULL, 0);
}
void
idnode_done(void)
{
idclass_link_t *il;
pthread_cond_signal(&idnode_cond);
pthread_join(idnode_tid, NULL);
pthread_mutex_lock(&idnode_mutex);
htsmsg_destroy(idnode_queue);
idnode_queue = NULL;
pthread_mutex_unlock(&idnode_mutex);
while ((il = RB_FIRST(&idclasses)) != NULL) {
RB_REMOVE(&idclasses, il, link);
free(il);
}
SKEL_FREE(idclasses_skel);
}
/**
@ -810,15 +830,13 @@ ic_cmp ( const idclass_link_t *a, const idclass_link_t *b )
static void
idclass_register(const idclass_t *idc)
{
static idclass_link_t *skel = NULL;
while (idc) {
if (!skel)
skel = calloc(1, sizeof(idclass_link_t));
skel->idc = idc;
if (RB_INSERT_SORTED(&idclasses, skel, link, ic_cmp))
SKEL_ALLOC(idclasses_skel);
idclasses_skel->idc = idc;
if (RB_INSERT_SORTED(&idclasses, idclasses_skel, link, ic_cmp))
break;
SKEL_USED(idclasses_skel);
tvhtrace("idnode", "register class %s", idc->ic_class);
skel = NULL;
idc = idc->ic_super;
}
}
@ -912,6 +930,9 @@ idnode_notify
{
const char *uuid = idnode_uuid_as_str(in);
if (!tvheadend_running)
return;
/* Forced */
if (chn || force) {
htsmsg_t *m = htsmsg_create_map();
@ -961,7 +982,7 @@ idnode_thread ( void *p )
pthread_mutex_lock(&idnode_mutex);
while (1) {
while (tvheadend_running) {
/* Get queue */
if (!idnode_queue) {
@ -995,6 +1016,7 @@ idnode_thread ( void *p )
pthread_mutex_lock(&idnode_mutex);
}
if (q) htsmsg_destroy(q);
pthread_mutex_unlock(&idnode_mutex);
return NULL;
}

View file

@ -109,6 +109,7 @@ typedef struct idnode_filter_ele
typedef LIST_HEAD(,idnode_filter_ele) idnode_filter_t;
void idnode_init(void);
void idnode_done(void);
int idnode_insert(idnode_t *in, const char *uuid, const idclass_t *idc);
void idnode_unlink(idnode_t *in);

View file

@ -199,7 +199,7 @@ imagecache_thread ( void *p )
imagecache_image_t *img;
pthread_mutex_lock(&global_lock);
while (1) {
while (tvheadend_running) {
/* Check we're enabled */
if (!imagecache_conf.enabled) {
@ -220,7 +220,9 @@ imagecache_thread ( void *p )
/* Fetch */
(void)imagecache_image_fetch(img);
}
pthread_mutex_unlock(&global_lock);
fprintf(stderr, "imagecache thread end\n");
return NULL;
}
@ -245,6 +247,10 @@ imagecache_timer_cb ( void *p )
/*
* Initialise
*/
#if ENABLE_IMAGECACHE
pthread_t imagecache_tid;
#endif
void
imagecache_init ( void )
{
@ -307,10 +313,7 @@ imagecache_init ( void )
/* Start threads */
#if ENABLE_IMAGECACHE
{
pthread_t tid;
tvhthread_create(&tid, NULL, imagecache_thread, NULL, 1);
}
tvhthread_create(&imagecache_tid, NULL, imagecache_thread, NULL, 0);
/* Re-try timer */
// TODO: this could be more efficient by being targetted, however
@ -320,6 +323,27 @@ imagecache_init ( void )
#endif
}
/*
* Shutdown
*/
void
imagecache_done ( void )
{
imagecache_image_t *img;
#if ENABLE_IMAGECACHE
pthread_cond_broadcast(&imagecache_cond);
pthread_join(imagecache_tid, NULL);
#endif
while ((img = RB_FIRST(&imagecache_by_url)) != NULL) {
RB_REMOVE(&imagecache_by_url, img, url_link);
RB_REMOVE(&imagecache_by_id, img, id_link);
free((void *)img->url);
free(img);
}
}
#if ENABLE_IMAGECACHE
/*

View file

@ -33,6 +33,7 @@ extern struct imagecache_config imagecache_conf;
extern pthread_mutex_t imagecache_mutex;
void imagecache_init ( void );
void imagecache_done ( void );
htsmsg_t *imagecache_get_config ( void );
int imagecache_set_config ( htsmsg_t *c );

View file

@ -295,7 +295,7 @@ struct mpegts_mux
* Functions
*/
void (*mm_delete) (mpegts_mux_t *mm);
void (*mm_delete) (mpegts_mux_t *mm, int delconf);
void (*mm_config_save) (mpegts_mux_t *mm);
void (*mm_display_name) (mpegts_mux_t*, char *buf, size_t len);
int (*mm_is_enabled) (mpegts_mux_t *mm);
@ -445,6 +445,9 @@ struct mpegts_input
pthread_t mi_thread_id;
th_pipe_t mi_thread_pipe;
int mi_delivery_running;
pthread_t mi_thread_table_id;
/*
* Functions
*/
@ -500,7 +503,7 @@ mpegts_input_t *mpegts_input_create0
mpegts_input_create0(calloc(1, sizeof(mpegts_input_t)),\
&mpegts_input_class, u, c)
void mpegts_input_delete ( mpegts_input_t *mi );
void mpegts_input_delete ( mpegts_input_t *mi, int delconf );
#define mpegts_input_find(u) idnode_find(u, &mpegts_input_class);
@ -515,6 +518,9 @@ void mpegts_network_register_builder
( const idclass_t *idc,
mpegts_network_t *(*build)(const idclass_t *idc, htsmsg_t *conf) );
void mpegts_network_unregister_builder
( const idclass_t *idc );
mpegts_network_t *mpegts_network_build
( const char *clazz, htsmsg_t *conf );
@ -532,8 +538,10 @@ extern const idclass_t mpegts_network_class;
mpegts_mux_t *mpegts_network_find_mux
(mpegts_network_t *mn, uint16_t onid, uint16_t tsid);
void mpegts_network_delete ( mpegts_network_t *mn );
void mpegts_network_class_delete ( const idclass_t *idc, int delconf );
void mpegts_network_delete ( mpegts_network_t *mn, int delconf );
void mpegts_network_schedule_initial_scan
( mpegts_network_t *mm );
@ -557,13 +565,13 @@ mpegts_mux_t *mpegts_mux_create0
#define mpegts_mux_find(u)\
idnode_find(u, &mpegts_mux_class)
#define mpegts_mux_delete_by_uuid(u)\
{ mpegts_mux_t *mm = mpegts_mux_find(u); if (mm) mm->mm_delete(mm); }
#define mpegts_mux_delete_by_uuid(u, delconf)\
{ mpegts_mux_t *mm = mpegts_mux_find(u); if (mm) mm->mm_delete(mm, delconf); }
void mpegts_mux_initial_scan_done ( mpegts_mux_t *mm, int log );
void mpegts_mux_initial_scan_fail ( mpegts_mux_t *mm );
void mpegts_mux_delete ( mpegts_mux_t *mm );
void mpegts_mux_delete ( mpegts_mux_t *mm, int delconf );
void mpegts_mux_save ( mpegts_mux_t *mm, htsmsg_t *c );
@ -599,7 +607,9 @@ size_t mpegts_input_recv_packets
(mpegts_input_t *mi, mpegts_mux_instance_t *mmi, uint8_t *tsb, size_t len,
int64_t *pcr, uint16_t *pcr_pid, const char *name);
void *mpegts_input_table_thread ( void *aux );
void mpegts_input_table_thread_start( mpegts_input_t *mi );
void mpegts_input_table_thread_stop( mpegts_input_t *mi );
int mpegts_input_is_free ( mpegts_input_t *mi );
@ -646,7 +656,7 @@ mpegts_service_t *mpegts_service_find
void mpegts_service_save ( mpegts_service_t *s, htsmsg_t *c );
void mpegts_service_delete ( service_t *s );
void mpegts_service_delete ( service_t *s, int delconf );
/*
* MPEG-TS event handler

View file

@ -276,4 +276,6 @@ int dvb_delsys2type ( enum fe_delivery_system ds );
#endif /* ENABLE_DVBAPI */
void dvb_done ( void );
#endif /* DVB_SUPPORT_H */

View file

@ -78,6 +78,20 @@ void dvb_charset_init ( void )
_charset_load_file();
}
/*
*
*/
void dvb_charset_done ( void )
{
dvb_charset_t *enc;
while ((enc = LIST_FIRST(&dvb_charset_list)) != NULL) {
LIST_REMOVE(enc, link);
free((void *)enc->charset);
free(enc);
}
}
/*
* Find default charset
*/

View file

@ -28,6 +28,7 @@ typedef struct dvb_charset {
} dvb_charset_t;
void dvb_charset_init ( void );
void dvb_charset_done ( void );
struct mpegts_network;
struct mpegts_mux;

View file

@ -33,6 +33,8 @@
#include <linux/dvb/version.h>
#include <linux/dvb/frontend.h>
SKEL_DECLARE(mpegts_table_state_skel, struct mpegts_table_state);
static int
psi_parse_pmt(mpegts_service_t *t, const uint8_t *ptr, int len);
@ -445,17 +447,16 @@ static struct mpegts_table_state *
mpegts_table_state_find
( mpegts_table_t *mt, int tableid, uint64_t extraid, int last )
{
static struct mpegts_table_state *st, *skel = NULL;
struct mpegts_table_state *st;
/* Find state */
if (!skel)
skel = calloc(1, sizeof(*skel));
skel->tableid = tableid;
skel->extraid = extraid;
st = RB_INSERT_SORTED(&mt->mt_state, skel, link, sect_cmp);
SKEL_ALLOC(mpegts_table_state_skel);
mpegts_table_state_skel->tableid = tableid;
mpegts_table_state_skel->extraid = extraid;
st = RB_INSERT_SORTED(&mt->mt_state, mpegts_table_state_skel, link, sect_cmp);
if (!st) {
st = skel;
skel = NULL;
st = mpegts_table_state_skel;
SKEL_USED(mpegts_table_state_skel);
mt->mt_incomplete++;
mpegts_table_state_reset(mt, st, last);
}

View file

@ -31,6 +31,7 @@
#include "tvheadend.h"
#include "dvb.h"
#include "dvb_charset_tables.h"
#include "../mpegts.h"
static int convert_iso_8859[16] = {
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -1, 11, 12, 13
@ -813,3 +814,17 @@ dvb_bandwidth ( fe_bandwidth_t bw )
}
#endif /* ENABLE_DVBAPI */
/**
*
*/
void dvb_done( void )
{
extern SKEL_DECLARE(mpegts_table_state_skel, struct mpegts_table_state);
extern SKEL_DECLARE(mpegts_pid_sub_skel, mpegts_pid_sub_t);
extern SKEL_DECLARE(mpegts_pid_skel, mpegts_pid_t);
SKEL_FREE(mpegts_table_state_skel);
SKEL_FREE(mpegts_pid_sub_skel);
SKEL_FREE(mpegts_pid_skel);
}

View file

@ -21,6 +21,7 @@
#define __IPTV_H__
void iptv_init ( void );
void iptv_done ( void );
#endif /* __IPTV_H__ */

View file

@ -32,13 +32,15 @@
#include <unistd.h>
#include <regex.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
/* **************************************************************************
* IPTV state
* *************************************************************************/
iptv_input_t iptv_input;
iptv_network_t iptv_network;
iptv_input_t *iptv_input;
iptv_network_t *iptv_network;
tvhpoll_t *iptv_poll;
pthread_t iptv_thread;
pthread_mutex_t iptv_lock;
@ -108,12 +110,12 @@ iptv_input_is_free ( mpegts_input_t *mi )
c++;
/* Limit reached */
if (iptv_network.in_max_streams && c >= iptv_network.in_max_streams) {
if (iptv_network->in_max_streams && c >= iptv_network->in_max_streams) {
return 0;
}
/* Bandwidth reached */
if (iptv_network.in_bw_limited) {
if (iptv_network->in_bw_limited) {
return 0;
}
@ -241,7 +243,7 @@ iptv_input_stop_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
im->mm_iptv_tsb = NULL;
/* Clear bw limit */
iptv_network.in_bw_limited = 0;
iptv_network->in_bw_limited = 0;
pthread_mutex_unlock(&iptv_lock);
}
@ -261,7 +263,7 @@ iptv_input_thread ( void *aux )
iptv_mux_t *im;
tvhpoll_event_t ev;
while ( 1 ) {
while ( tvheadend_running ) {
nfds = tvhpoll_wait(iptv_poll, &ev, 1, -1);
if ( nfds < 0 ) {
tvhlog(LOG_ERR, "iptv", "poll() error %s, sleeping 1 second",
@ -298,23 +300,23 @@ void
iptv_input_recv_packets ( iptv_mux_t *im, size_t off, size_t len )
{
static time_t t1 = 0, t2;
iptv_network.in_bps += len * 8;
iptv_network->in_bps += len * 8;
time(&t2);
if (t2 != t1) {
if (iptv_network.in_max_bandwidth &&
iptv_network.in_bps > iptv_network.in_max_bandwidth * 1024) {
if (!iptv_network.in_bw_limited) {
if (iptv_network->in_max_bandwidth &&
iptv_network->in_bps > iptv_network->in_max_bandwidth * 1024) {
if (!iptv_network->in_bw_limited) {
tvhinfo("iptv", "bandwidth limited exceeded");
iptv_network.in_bw_limited = 1;
iptv_network->in_bw_limited = 1;
}
}
iptv_network.in_bps = 0;
iptv_network->in_bps = 0;
t1 = t2;
}
/* Pass on */
im->mm_iptv_pos
= mpegts_input_recv_packets((mpegts_input_t*)&iptv_input,
= mpegts_input_recv_packets((mpegts_input_t*)iptv_input,
im->mm_active,
im->mm_iptv_tsb + off,
im->mm_iptv_pos + len - off,
@ -423,7 +425,6 @@ iptv_network_config_save ( mpegts_network_t *mn )
void iptv_init ( void )
{
pthread_t tid;
htsmsg_t *conf;
const char *uuid = NULL;
@ -431,48 +432,64 @@ void iptv_init ( void )
iptv_http_init();
iptv_udp_init();
iptv_input = calloc(1, sizeof(iptv_input_t));
/* Init Input */
mpegts_input_create0((mpegts_input_t*)&iptv_input,
mpegts_input_create0((mpegts_input_t*)iptv_input,
&iptv_input_class, NULL, NULL);
iptv_input.mi_start_mux = iptv_input_start_mux;
iptv_input.mi_stop_mux = iptv_input_stop_mux;
iptv_input.mi_is_free = iptv_input_is_free;
iptv_input.mi_get_weight = iptv_input_get_weight;
iptv_input.mi_display_name = iptv_input_display_name;
iptv_input.mi_enabled = 1;
iptv_input->mi_start_mux = iptv_input_start_mux;
iptv_input->mi_stop_mux = iptv_input_stop_mux;
iptv_input->mi_is_free = iptv_input_is_free;
iptv_input->mi_get_weight = iptv_input_get_weight;
iptv_input->mi_display_name = iptv_input_display_name;
iptv_input->mi_enabled = 1;
/* Load settings */
if ((conf = hts_settings_load("input/iptv/config")))
uuid = htsmsg_get_str(conf, "uuid");
iptv_network = calloc(1, sizeof(iptv_network_t));
/* Init Network */
mpegts_network_create0((mpegts_network_t*)&iptv_network,
mpegts_network_create0((mpegts_network_t*)iptv_network,
&iptv_network_class, uuid, "IPTV Network", conf);
iptv_network.mn_create_service = iptv_network_create_service;
iptv_network.mn_mux_class = iptv_network_mux_class;
iptv_network.mn_mux_create2 = iptv_network_create_mux2;
iptv_network.mn_config_save = iptv_network_config_save;
iptv_network->mn_create_service = iptv_network_create_service;
iptv_network->mn_mux_class = iptv_network_mux_class;
iptv_network->mn_mux_create2 = iptv_network_create_mux2;
iptv_network->mn_config_save = iptv_network_config_save;
/* Defaults */
if (!conf) {
iptv_network.mn_skipinitscan = 1;
iptv_network->mn_skipinitscan = 1;
}
/* Link */
mpegts_input_set_network((mpegts_input_t*)&iptv_input,
(mpegts_network_t*)&iptv_network);
mpegts_input_set_network((mpegts_input_t*)iptv_input,
(mpegts_network_t*)iptv_network);
/* Set table thread */
tvhthread_create(&tid, NULL, mpegts_input_table_thread, &iptv_input, 1);
mpegts_input_table_thread_start((mpegts_input_t *)iptv_input);
/* Setup TS thread */
iptv_poll = tvhpoll_create(10);
pthread_mutex_init(&iptv_lock, NULL);
tvhthread_create(&iptv_thread, NULL, iptv_input_thread, NULL, 1);
tvhthread_create(&iptv_thread, NULL, iptv_input_thread, NULL, 0);
/* Load config */
iptv_mux_load_all();
}
void iptv_done ( void )
{
mpegts_input_table_thread_stop((mpegts_input_t *)iptv_input);
pthread_kill(iptv_thread, SIGTERM);
pthread_join(iptv_thread, NULL);
tvhpoll_destroy(iptv_poll);
pthread_mutex_lock(&global_lock);
mpegts_network_delete((mpegts_network_t *)iptv_network, 0);
mpegts_input_delete((mpegts_input_t *)iptv_input, 0);
pthread_mutex_unlock(&global_lock);
}
/******************************************************************************
* Editor Configuration
*

View file

@ -65,12 +65,13 @@ iptv_mux_config_save ( mpegts_mux_t *mm )
}
static void
iptv_mux_delete ( mpegts_mux_t *mm )
iptv_mux_delete ( mpegts_mux_t *mm, int delconf )
{
hts_settings_remove("input/iptv/muxes/%s/config",
if (delconf)
hts_settings_remove("input/iptv/muxes/%s/config",
idnode_uuid_as_str(&mm->mm_id));
mpegts_mux_delete(mm);
mpegts_mux_delete(mm, delconf);
}
static void

View file

@ -99,8 +99,8 @@ iptv_service_t *iptv_service_create0
( iptv_mux_t *im, uint16_t sid, uint16_t pmt_pid,
const char *uuid, htsmsg_t *conf );
extern iptv_input_t iptv_input;
extern iptv_network_t iptv_network;
extern iptv_input_t *iptv_input;
extern iptv_network_t *iptv_network;
void iptv_mux_load_all ( void );

View file

@ -22,6 +22,8 @@
void linuxdvb_init ( int mask );
void linuxdvb_done ( void );
idnode_set_t *linuxdvb_root ( void );
#endif /* __TVH_LINUX_DVB_H__ */

View file

@ -45,3 +45,11 @@ void linuxdvb_init ( int adapter_mask )
/* Initialsie devices */
linuxdvb_adapter_init();
}
void linuxdvb_done ( void )
{
linuxdvb_network_done();
linuxdvb_adapter_done();
dvb_charset_done();
scanfile_done();
}

View file

@ -144,6 +144,7 @@ linuxdvb_adapter_create
/* Setup */
sprintf(buf, "%s [%s]", path, dfi->name);
free(la->la_rootpath);
la->la_rootpath = strdup(path);
la->la_name = strdup(buf);
la->la_dvb_number = number;
@ -271,6 +272,7 @@ linuxdvb_adapter_add ( const char *path )
/* Create */
if (!(la = linuxdvb_adapter_create(uuid, conf, path, a, &dfi))) {
tvhlog(LOG_ERR, "linuxdvb", "failed to create %s", path);
htsmsg_destroy(conf);
return; // Note: save to return here as global_lock is held
}
}
@ -295,6 +297,7 @@ linuxdvb_adapter_add ( const char *path )
}
#endif
pthread_mutex_unlock(&global_lock);
htsmsg_destroy(conf);
}
/* Relock before exit */
@ -334,6 +337,8 @@ linuxdvb_adapter_del ( const char *path )
/* Delete */
tvh_hardware_delete((tvh_hardware_t*)la);
free(la);
}
}
@ -424,3 +429,22 @@ linuxdvb_adapter_init ( void )
linuxdvb_adapter_scan();
}
}
void
linuxdvb_adapter_done ( void )
{
linuxdvb_adapter_t *la;
tvh_hardware_t *th, *n;
pthread_mutex_lock(&global_lock);
fsmonitor_del("/dev/dvb", &devdvbmon);
fsmonitor_del("/dev", &devmon);
for (th = LIST_FIRST(&tvh_hardware); th != NULL; th = n) {
n = LIST_NEXT(th, th_link);
if (idnode_is_instance(&th->th_id, &linuxdvb_adapter_class)) {
la = (linuxdvb_adapter_t*)th;
linuxdvb_adapter_del(la->la_rootpath);
}
}
pthread_mutex_unlock(&global_lock);
}

View file

@ -704,7 +704,7 @@ linuxdvb_frontend_input_thread ( void *aux )
tvhpoll_add(efd, ev, 2);
/* Read */
while (1) {
while (tvheadend_running) {
nfds = tvhpoll_wait(efd, ev, 1, 10);
if (nfds < 1) continue;
if (ev[0].data.fd != dvr) break;
@ -922,7 +922,6 @@ linuxdvb_frontend_create
char id[12], name[256];
linuxdvb_frontend_t *lfe;
htsmsg_t *scconf = NULL;
pthread_t tid;
/* Internal config ID */
snprintf(id, sizeof(id), "%s #%d", dvb_type2str(dfi->type), number);
@ -986,7 +985,7 @@ linuxdvb_frontend_create
pthread_cond_init(&lfe->lfe_dvr_cond, NULL);
/* Start table thread */
tvhthread_create(&tid, NULL, mpegts_input_table_thread, lfe, 1);
mpegts_input_table_thread_start((mpegts_input_t *)lfe);
/* Satconf */
if (conf) {
@ -1042,6 +1041,8 @@ linuxdvb_frontend_delete ( linuxdvb_frontend_t *lfe )
if (lfe->lfe_fe_fd > 0)
close(lfe->lfe_fe_fd);
mpegts_input_table_thread_stop((mpegts_input_t *)lfe);
/* Remove from adapter */
LIST_REMOVE(lfe, lfe_link);
@ -1055,7 +1056,7 @@ linuxdvb_frontend_delete ( linuxdvb_frontend_t *lfe )
linuxdvb_satconf_delete(lfe->lfe_satconf, 0);
/* Finish */
mpegts_input_delete((mpegts_input_t*)lfe);
mpegts_input_delete((mpegts_input_t*)lfe, 0);
}
/******************************************************************************

View file

@ -36,7 +36,7 @@
* *************************************************************************/
static void
linuxdvb_mux_delete ( mpegts_mux_t *mm );
linuxdvb_mux_delete ( mpegts_mux_t *mm, int delconf );
extern const idclass_t mpegts_mux_class;
@ -611,15 +611,16 @@ linuxdvb_mux_create_instances ( mpegts_mux_t *mm )
}
static void
linuxdvb_mux_delete ( mpegts_mux_t *mm )
linuxdvb_mux_delete ( mpegts_mux_t *mm, int delconf )
{
/* Remove config */
hts_settings_remove("input/linuxdvb/networks/%s/muxes/%s",
if (delconf)
hts_settings_remove("input/linuxdvb/networks/%s/muxes/%s",
idnode_uuid_as_str(&mm->mm_network->mn_id),
idnode_uuid_as_str(&mm->mm_id));
/* Delete the mux */
mpegts_mux_delete(mm);
mpegts_mux_delete(mm, delconf);
}
/* **************************************************************************

View file

@ -51,7 +51,7 @@ linuxdvb_network_class_delete ( idnode_t *in )
idnode_uuid_as_str(in));
/* Parent delete */
mpegts_network_delete(mn);
mpegts_network_delete(mn, 1);
}
static const void *
@ -356,6 +356,13 @@ linuxdvb_network_builder
return (mpegts_network_t*)linuxdvb_network_create0(NULL, idc, conf);
}
static const idclass_t* linuxdvb_network_classes[] = {
&linuxdvb_network_dvbt_class,
&linuxdvb_network_dvbc_class,
&linuxdvb_network_dvbs_class,
&linuxdvb_network_atsc_class,
};
void linuxdvb_network_init ( void )
{
htsmsg_t *c, *e;
@ -363,16 +370,10 @@ void linuxdvb_network_init ( void )
const char *s;
int i;
const idclass_t* classes[] = {
&linuxdvb_network_dvbt_class,
&linuxdvb_network_dvbc_class,
&linuxdvb_network_dvbs_class,
&linuxdvb_network_atsc_class,
};
/* Register class builders */
for (i = 0; i < ARRAY_SIZE(classes); i++)
mpegts_network_register_builder(classes[i], linuxdvb_network_builder);
for (i = 0; i < ARRAY_SIZE(linuxdvb_network_classes); i++)
mpegts_network_register_builder(linuxdvb_network_classes[i],
linuxdvb_network_builder);
/* Load settings */
if (!(c = hts_settings_load_r(1, "input/linuxdvb/networks")))
@ -382,9 +383,9 @@ void linuxdvb_network_init ( void )
if (!(e = htsmsg_get_map_by_field(f))) continue;
if (!(e = htsmsg_get_map(e, "config"))) continue;
if (!(s = htsmsg_get_str(e, "class"))) continue;
for (i = 0; i < ARRAY_SIZE(classes); i++) {
if(!strcmp(classes[i]->ic_class, s)) {
(void)linuxdvb_network_create0(f->hmf_name, classes[i], e);
for (i = 0; i < ARRAY_SIZE(linuxdvb_network_classes); i++) {
if(!strcmp(linuxdvb_network_classes[i]->ic_class, s)) {
(void)linuxdvb_network_create0(f->hmf_name, linuxdvb_network_classes[i], e);
break;
}
}
@ -392,6 +393,19 @@ void linuxdvb_network_init ( void )
htsmsg_destroy(c);
}
void linuxdvb_network_done ( void )
{
int i;
pthread_mutex_lock(&global_lock);
/* Unregister class builders */
for (i = 0; i < ARRAY_SIZE(linuxdvb_network_classes); i++) {
mpegts_network_unregister_builder(linuxdvb_network_classes[i]);
mpegts_network_class_delete(linuxdvb_network_classes[i], 0);
}
pthread_mutex_unlock(&global_lock);
}
/* ****************************************************************************
* Search
* ***************************************************************************/

View file

@ -207,6 +207,8 @@ struct linuxdvb_en50494
void linuxdvb_adapter_init ( void );
void linuxdvb_adapter_done ( void );
void linuxdvb_adapter_save ( linuxdvb_adapter_t *la );
int linuxdvb_adapter_is_free ( linuxdvb_adapter_t *la );
@ -245,6 +247,7 @@ struct linuxdvb_network
};
void linuxdvb_network_init ( void );
void linuxdvb_network_done ( void );
linuxdvb_network_t *linuxdvb_network_find_by_uuid(const char *uuid);
linuxdvb_network_t *linuxdvb_network_create0

View file

@ -1096,7 +1096,7 @@ linuxdvb_satconf_ele_destroy ( linuxdvb_satconf_ele_t *ls )
if (ls->ls_switch) linuxdvb_switch_destroy(ls->ls_switch);
if (ls->ls_rotor) linuxdvb_rotor_destroy(ls->ls_rotor);
if (ls->ls_en50494) linuxdvb_en50494_destroy(ls->ls_en50494);
mpegts_input_delete((mpegts_input_t*)ls);
mpegts_input_delete((mpegts_input_t*)ls, 1);
}
linuxdvb_satconf_ele_t *
@ -1171,8 +1171,10 @@ linuxdvb_satconf_delete ( linuxdvb_satconf_t *ls, int delconf )
linuxdvb_rotor_destroy(lse->ls_rotor);
if (lse->ls_en50494)
linuxdvb_en50494_destroy(lse->ls_en50494);
mpegts_input_delete((mpegts_input_t*)lse);
mpegts_input_delete((mpegts_input_t*)lse, delconf);
}
idnode_unlink(&ls->ls_id);
free(ls);
}
/******************************************************************************
@ -1228,6 +1230,7 @@ void
linuxdvb_diseqc_destroy ( linuxdvb_diseqc_t *ld )
{
idnode_unlink(&ld->ld_id);
free((void *)ld->ld_type);
}
int

View file

@ -428,6 +428,43 @@ scanfile_init ( void )
scanfile_load_dir(path, NULL, 0);
}
/*
* Destroy the mux list
*/
static void
scanfile_done_region( scanfile_region_list_t *list )
{
scanfile_region_t *reg;
scanfile_network_t *net;
dvb_mux_conf_t *mux;
while ((reg = LIST_FIRST(list)) != NULL) {
LIST_REMOVE(reg, sfr_link);
while ((net = LIST_FIRST(&reg->sfr_networks)) != NULL) {
LIST_REMOVE(net, sfn_link);
while ((mux = LIST_FIRST(&net->sfn_muxes)) != NULL) {
LIST_REMOVE(mux, dmc_link);
free(mux);
}
free((void *)net->sfn_id);
free((void *)net->sfn_name);
free(net);
}
free((void *)reg->sfr_id);
free((void *)reg->sfr_name);
free(reg);
}
}
void
scanfile_done ( void )
{
scanfile_done_region(&scanfile_regions_DVBS);
scanfile_done_region(&scanfile_regions_DVBT);
scanfile_done_region(&scanfile_regions_DVBC);
scanfile_done_region(&scanfile_regions_ATSC);
}
/*
* Find scanfile
*/

View file

@ -40,6 +40,7 @@ extern scanfile_region_list_t scanfile_regions_DVBS;
extern scanfile_region_list_t scanfile_regions_ATSC;
void scanfile_init ( void );
void scanfile_done ( void );
scanfile_network_t *scanfile_find ( const char *id );

View file

@ -27,6 +27,9 @@
#include <pthread.h>
#include <assert.h>
SKEL_DECLARE(mpegts_pid_sub_skel, mpegts_pid_sub_t);
/* **************************************************************************
* Class definition
* *************************************************************************/
@ -166,16 +169,14 @@ mpegts_input_open_pid
mpegts_pid_t *mp;
assert(owner != NULL);
if ((mp = mpegts_mux_find_pid(mm, pid, 1))) {
static mpegts_pid_sub_t *skel = NULL;
if (!skel)
skel = calloc(1, sizeof(mpegts_pid_sub_t));
skel->mps_type = type;
skel->mps_owner = owner;
if (!RB_INSERT_SORTED(&mp->mp_subs, skel, mps_link, mps_cmp)) {
SKEL_ALLOC(mpegts_pid_sub_skel);
mpegts_pid_sub_skel->mps_type = type;
mpegts_pid_sub_skel->mps_owner = owner;
if (!RB_INSERT_SORTED(&mp->mp_subs, mpegts_pid_sub_skel, mps_link, mps_cmp)) {
mm->mm_display_name(mm, buf, sizeof(buf));
tvhdebug("mpegts", "%s - open PID %04X (%d) [%d/%p]",
buf, mp->mp_pid, mp->mp_pid, type, owner);
skel = NULL;
SKEL_USED(mpegts_pid_sub_skel);
}
}
return mp;
@ -486,30 +487,60 @@ mpegts_input_table_dispatch ( mpegts_mux_t *mm, mpegts_table_feed_t *mtf )
}
}
void *
static void *
mpegts_input_table_thread ( void *aux )
{
mpegts_table_feed_t *mtf;
mpegts_input_t *mi = aux;
while (1) {
pthread_mutex_lock(&mi->mi_delivery_mutex);
while (mi->mi_delivery_running) {
/* Wait for data */
pthread_mutex_lock(&mi->mi_delivery_mutex);
while(!(mtf = TAILQ_FIRST(&mi->mi_table_feed)))
while(!(mtf = TAILQ_FIRST(&mi->mi_table_feed))) {
if (!mi->mi_delivery_running)
break;
pthread_cond_wait(&mi->mi_table_feed_cond, &mi->mi_delivery_mutex);
TAILQ_REMOVE(&mi->mi_table_feed, mtf, mtf_link);
pthread_mutex_unlock(&mi->mi_delivery_mutex);
}
if (mtf)
TAILQ_REMOVE(&mi->mi_table_feed, mtf, mtf_link);
/* Process */
pthread_mutex_lock(&global_lock);
mpegts_input_table_dispatch(mtf->mtf_mux, mtf);
pthread_mutex_unlock(&global_lock);
if (mtf) {
pthread_mutex_unlock(&mi->mi_delivery_mutex);
pthread_mutex_lock(&global_lock);
mpegts_input_table_dispatch(mtf->mtf_mux, mtf);
pthread_mutex_unlock(&global_lock);
free(mtf);
pthread_mutex_lock(&mi->mi_delivery_mutex);
}
}
while ((mtf = TAILQ_FIRST(&mi->mi_table_feed)) != NULL) {
TAILQ_REMOVE(&mi->mi_table_feed, mtf, mtf_link);
free(mtf);
}
pthread_mutex_unlock(&mi->mi_delivery_mutex);
return NULL;
}
void
mpegts_input_table_thread_start( mpegts_input_t *mi )
{
mi->mi_delivery_running = 1;
tvhthread_create(&mi->mi_thread_table_id, NULL,
mpegts_input_table_thread, mi, 0);
}
void
mpegts_input_table_thread_stop( mpegts_input_t *mi )
{
pthread_mutex_lock(&mi->mi_delivery_mutex);
mi->mi_delivery_running = 0;
pthread_cond_signal(&mi->mi_table_feed_cond);
pthread_mutex_unlock(&mi->mi_delivery_mutex);
pthread_join(mi->mi_thread_table_id, NULL);
}
void
mpegts_input_flush_mux
( mpegts_input_t *mi, mpegts_mux_t *mm )
@ -667,14 +698,16 @@ mpegts_input_create0
}
void
mpegts_input_delete ( mpegts_input_t *mi )
mpegts_input_delete ( mpegts_input_t *mi, int delconf )
{
mpegts_input_set_network(mi, NULL);
idnode_unlink(&mi->ti_id);
pthread_mutex_destroy(&mi->mi_delivery_mutex);
pthread_cond_destroy(&mi->mi_table_feed_cond);
tvh_pipe_close(&mi->mi_thread_pipe);
LIST_REMOVE(mi, ti_link);
LIST_REMOVE(mi, mi_global_link);
free(mi->mi_name);
free(mi);
}

View file

@ -25,6 +25,8 @@
#include <assert.h>
SKEL_DECLARE(mpegts_pid_skel, mpegts_pid_t);
static void
mpegts_mux_initial_scan_timeout ( void *aux );
static void
@ -180,7 +182,7 @@ static void
mpegts_mux_class_delete ( idnode_t *self )
{
mpegts_mux_t *mm = (mpegts_mux_t*)self;
if (mm->mm_delete) mm->mm_delete(mm);
if (mm->mm_delete) mm->mm_delete(mm, 1);
}
static const void *
@ -330,7 +332,7 @@ mpegts_mux_display_name ( mpegts_mux_t *mm, char *buf, size_t len )
}
void
mpegts_mux_delete ( mpegts_mux_t *mm )
mpegts_mux_delete ( mpegts_mux_t *mm, int delconf )
{
mpegts_mux_instance_t *mmi;
mpegts_network_t *mn = mm->mm_network;
@ -354,7 +356,7 @@ mpegts_mux_delete ( mpegts_mux_t *mm )
/* Delete services */
while ((s = LIST_FIRST(&mm->mm_services))) {
service_destroy((service_t*)s);
service_destroy((service_t*)s, delconf);
}
/* Free memory */
@ -527,6 +529,7 @@ mpegts_mux_stop ( mpegts_mux_t *mm, int force )
tvhtrace("mpegts", "%s - flush tables", buf);
mpegts_table_flush_all(mm);
tvhtrace("mpegts", "%s - mi=%p", buf, (void *)mi);
/* Flush table data queue */
if (mi)
mpegts_input_flush_mux(mi, mm);
@ -905,14 +908,12 @@ mpegts_mux_find_pid ( mpegts_mux_t *mm, int pid, int create )
skel.mp_pid = pid;
mp = RB_FIND(&mm->mm_pids, &skel, mp_link, mp_cmp);
} else {
static mpegts_pid_t *skel = NULL;
if (!skel)
skel = calloc(1, sizeof(mpegts_pid_t));
skel->mp_pid = pid;
mp = RB_INSERT_SORTED(&mm->mm_pids, skel, mp_link, mp_cmp);
SKEL_ALLOC(mpegts_pid_skel);
mpegts_pid_skel->mp_pid = pid;
mp = RB_INSERT_SORTED(&mm->mm_pids, mpegts_pid_skel, mp_link, mp_cmp);
if (!mp) {
mp = skel;
skel = NULL;
mp = mpegts_pid_skel;
SKEL_USED(mpegts_pid_skel);
mp->mp_fd = -1;
}
}

View file

@ -210,7 +210,7 @@ mpegts_network_mux_create2
void
mpegts_network_delete
( mpegts_network_t *mn )
( mpegts_network_t *mn, int delconf )
{
mpegts_input_t *mi;
mpegts_mux_t *mm;
@ -220,7 +220,7 @@ mpegts_network_delete
/* Delete all muxes */
while ((mm = LIST_FIRST(&mn->mn_muxes))) {
mm->mm_delete(mm);
mm->mm_delete(mm, delconf);
}
/* Check */
@ -340,6 +340,18 @@ mpegts_network_create0
return mn;
}
void
mpegts_network_class_delete(const idclass_t *idc, int delconf)
{
mpegts_network_t *mn, *n;
for (mn = LIST_FIRST(&mpegts_network_all); mn != NULL; mn = n) {
n = LIST_NEXT(mn, mn_global_link);
if (mn->mn_id.in_class == idc)
mpegts_network_delete(mn, delconf);
}
}
int
mpegts_network_set_nid
( mpegts_network_t *mn, uint16_t nid )
@ -384,6 +396,20 @@ mpegts_network_register_builder
LIST_INSERT_HEAD(&mpegts_network_builders, mnb, link);
}
void
mpegts_network_unregister_builder
( const idclass_t *idc )
{
mpegts_network_builder_t *mnb;
LIST_FOREACH(mnb, &mpegts_network_builders, link) {
if (mnb->idc == idc) {
LIST_REMOVE(mnb, link);
free(mnb);
return;
}
}
}
mpegts_network_t *
mpegts_network_build
( const char *clazz, htsmsg_t *conf )

View file

@ -338,13 +338,14 @@ mpegts_service_provider_name ( service_t *s )
}
void
mpegts_service_delete ( service_t *t )
mpegts_service_delete ( service_t *t, int delconf )
{
mpegts_service_t *ms = (mpegts_service_t*)t;
mpegts_mux_t *mm = ms->s_dvb_mux;
/* Remove config */
hts_settings_remove("input/linuxdvb/networks/%s/muxes/%s/services/%s",
if (delconf)
hts_settings_remove("input/linuxdvb/networks/%s/muxes/%s/services/%s",
idnode_uuid_as_str(&mm->mm_network->mn_id),
idnode_uuid_as_str(&mm->mm_id),
idnode_uuid_as_str(&t->s_id));
@ -354,6 +355,7 @@ mpegts_service_delete ( service_t *t )
free(ms->s_dvb_provider);
free(ms->s_dvb_charset);
LIST_REMOVE(ms, s_dvb_mux_link);
sbuf_free(&ms->s_tsbuf);
// Note: the ultimate deletion and removal from the idnode list
// is done in service_destroy

View file

@ -240,7 +240,6 @@ tsfile_input_start_mux ( mpegts_input_t *mi, mpegts_mux_instance_t *t )
mpegts_input_t *
tsfile_input_create ( int idx )
{
pthread_t tid;
mpegts_input_t *mi;
/* Create object */
@ -254,7 +253,7 @@ tsfile_input_create ( int idx )
mi->mi_name = strdup("TSFile");
/* Start table thread */
tvhthread_create(&tid, NULL, mpegts_input_table_thread, mi, 1);
mpegts_input_table_thread_start(mi);
return mi;
}

View file

@ -668,3 +668,22 @@ const lang_code_t **lang_code_split2 ( const char *codes )
return ret;
}
static void lang_code_free( lang_code_lookup_t *l )
{
lang_code_lookup_element_t *element;
if (l == NULL)
return;
while ((element = RB_FIRST(l)) != NULL) {
RB_REMOVE(l, element, link);
free(element);
}
free(l);
}
void lang_code_done( void )
{
lang_code_free(lang_codes_code2b);
lang_code_free(lang_codes_code1);
lang_code_free(lang_codes_code2t);
}

View file

@ -48,4 +48,6 @@ typedef struct lang_code_lookup_element {
typedef RB_HEAD(lang_code_lookup, lang_code_lookup_element) lang_code_lookup_t;
void lang_code_done( void );
#endif /* __TVH_LANG_CODES_H__ */

View file

@ -22,6 +22,9 @@
#include "redblack.h"
#include "lang_codes.h"
#include "lang_str.h"
#include "tvheadend.h"
SKEL_DECLARE(lang_str_ele_skel, lang_str_ele_t);
/* ************************************************************************
* Support
@ -107,7 +110,6 @@ static int _lang_str_add
( lang_str_t *ls, const char *str, const char *lang, int update, int append )
{
int save = 0;
static lang_str_ele_t *skel = NULL;
lang_str_ele_t *e;
if (!str) return 0;
@ -116,14 +118,14 @@ static int _lang_str_add
if (!(lang = lang_code_get(lang))) return 0;
/* Create skel */
if (!skel) skel = calloc(1, sizeof(lang_str_ele_t));
skel->lang = lang;
SKEL_ALLOC(lang_str_ele_skel);
lang_str_ele_skel->lang = lang;
/* Create */
e = RB_INSERT_SORTED(ls, skel, link, _lang_cmp);
e = RB_INSERT_SORTED(ls, lang_str_ele_skel, link, _lang_cmp);
if (!e) {
skel->str = strdup(str);
skel = NULL;
lang_str_ele_skel->str = strdup(str);
SKEL_USED(lang_str_ele_skel);
save = 1;
/* Append */
@ -189,3 +191,8 @@ lang_str_t *lang_str_deserialize ( htsmsg_t *m, const char *n )
}
return ret;
}
void lang_str_done( void )
{
SKEL_FREE(lang_str_ele_skel);
}

View file

@ -52,4 +52,7 @@ void lang_str_serialize
lang_str_t *lang_str_deserialize
( htsmsg_t *m, const char *f );
/* Init/Done */
void lang_str_done( void );
#endif /* __TVH_LANG_STR_H__ */

View file

@ -59,6 +59,7 @@
#include "imagecache.h"
#include "timeshift.h"
#include "fsmonitor.h"
#include "lang_codes.h"
#if ENABLE_LIBAV
#include "libav.h"
#include "plumbing/transcoding.h"
@ -68,6 +69,8 @@
#include <sys/prctl.h>
#endif
pthread_t main_tid;
/* Command line option struct */
typedef struct str_list
{
@ -169,10 +172,14 @@ handle_sigpipe(int x)
return;
}
static void
void
doexit(int x)
{
if (pthread_self() != main_tid)
pthread_kill(main_tid, SIGTERM);
pthread_cond_signal(&gtimer_cond);
tvheadend_running = 0;
signal(x, doexit);
}
static int
@ -424,6 +431,8 @@ main(int argc, char **argv)
const char *log_debug = NULL, *log_trace = NULL;
char buf[512];
main_tid = pthread_self();
/* Setup global mutexes */
pthread_mutex_init(&ffmpeg_lock, NULL);
pthread_mutex_init(&fork_lock, NULL);
@ -704,6 +713,8 @@ main(int argc, char **argv)
umask(0);
}
tvheadend_running = 1;
/* Start log thread (must be done post fork) */
tvhlog_start();
@ -789,9 +800,7 @@ main(int argc, char **argv)
if(opt_subscribe != NULL)
subscription_dummy_join(opt_subscribe, 1);
#ifdef CONFIG_AVAHI
avahi_init();
#endif
epg_updated(); // cleanup now all prev ref's should have been created
@ -801,7 +810,6 @@ main(int argc, char **argv)
* Wait for SIGTERM / SIGINT, but only in this thread
*/
tvheadend_running = 1;
sigemptyset(&set);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGINT);
@ -822,21 +830,55 @@ main(int argc, char **argv)
mainloop();
tvhftrace("main", htsp_done);
tvhftrace("main", http_server_done);
tvhftrace("main", webui_done);
tvhftrace("main", http_client_done);
tvhftrace("main", fsmonitor_done);
#if ENABLE_IPTV
tvhftrace("main", iptv_done);
#endif
#if ENABLE_LINUXDVB
tvhftrace("main", linuxdvb_done);
#endif
// Note: the locking is obviously a bit redundant, but without
// we need to disable the gtimer_arm call in epg_save()
pthread_mutex_lock(&global_lock);
epg_save(NULL);
tvhftrace("main", epg_save);
#if ENABLE_TIMESHIFT
timeshift_term();
tvhftrace("main", timeshift_term);
#endif
pthread_mutex_unlock(&global_lock);
tvhftrace("main", epggrab_done);
tvhftrace("main", tcp_server_done);
tvhftrace("main", subscription_done);
tvhftrace("main", descrambler_done);
tvhftrace("main", service_mapper_done);
tvhftrace("main", service_done);
tvhftrace("main", channel_done);
tvhftrace("main", dvr_done);
tvhftrace("main", access_done);
tvhftrace("main", epg_done);
tvhftrace("main", avahi_done);
tvhftrace("main", imagecache_done);
tvhftrace("main", idnode_done);
tvhftrace("main", lang_code_done);
tvhftrace("main", api_done);
tvhftrace("main", config_done);
tvhftrace("main", hts_settings_done);
tvhftrace("main", dvb_done);
tvhftrace("main", lang_str_done);
tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");
tvhlog_end();
if(opt_fork)
unlink(opt_pidpath);
free(opt_tsfile.str);
return 0;
}

View file

@ -239,6 +239,8 @@ stream_clean(elementary_stream_t *st)
void
service_stream_destroy(service_t *t, elementary_stream_t *es)
{
caid_t *c;
if(t->s_status == SERVICE_RUNNING)
stream_clean(es);
@ -246,6 +248,12 @@ service_stream_destroy(service_t *t, elementary_stream_t *es)
avgstat_flush(&es->es_cc_errors);
TAILQ_REMOVE(&t->s_components, es, es_link);
while ((c = LIST_FIRST(&es->es_caids)) != NULL) {
LIST_REMOVE(c, link);
free(c);
}
free(es->es_section);
free(es->es_nicename);
free(es);
@ -441,8 +449,10 @@ service_find_instance
void
service_unref(service_t *t)
{
if((atomic_add(&t->s_refcount, -1)) == 1)
if((atomic_add(&t->s_refcount, -1)) == 1) {
free(t->s_nicename);
free(t);
}
}
@ -461,14 +471,14 @@ service_ref(service_t *t)
* Destroy a service
*/
void
service_destroy(service_t *t)
service_destroy(service_t *t, int delconf)
{
elementary_stream_t *st;
th_subscription_t *s;
channel_service_mapping_t *csm;
if(t->s_delete != NULL)
t->s_delete(t);
t->s_delete(t, delconf);
lock_assert(&global_lock);
@ -964,7 +974,7 @@ service_saver(void *aux)
int restart;
pthread_mutex_lock(&pending_save_mutex);
while(1) {
while(tvheadend_running) {
if((t = TAILQ_FIRST(&pending_save_queue)) == NULL) {
pthread_cond_wait(&pending_save_cond, &pending_save_mutex);
@ -996,17 +1006,24 @@ service_saver(void *aux)
/**
*
*/
pthread_t service_saver_tid;
void
service_init(void)
{
pthread_t tid;
TAILQ_INIT(&pending_save_queue);
TAILQ_INIT(&service_all);
pthread_mutex_init(&pending_save_mutex, NULL);
pthread_cond_init(&pending_save_cond, NULL);
tvhthread_create(&tid, NULL, service_saver, NULL, 1);
tvhthread_create(&service_saver_tid, NULL, service_saver, NULL, 0);
}
void
service_done(void)
{
pthread_cond_signal(&pending_save_cond);
pthread_join(service_saver_tid, NULL);
}
/**
*

View file

@ -283,7 +283,7 @@ typedef struct service {
int (*s_grace_period)(struct service *t);
void (*s_delete)(struct service *t);
void (*s_delete)(struct service *t, int delconf);
/**
* Channel info
@ -426,6 +426,7 @@ typedef struct service {
void service_init(void);
void service_done(void);
int service_start(service_t *t, int instance);
@ -466,7 +467,7 @@ int service_is_other(service_t *t);
int service_is_encrypted ( service_t *t );
void service_destroy(service_t *t);
void service_destroy(service_t *t, int delconf);
void service_remove_subscriber(service_t *t, struct th_subscription *s,
int reason);

View file

@ -44,13 +44,21 @@ static void *service_mapper_thread ( void *p );
/**
* Initialise
*/
pthread_t service_mapper_tid;
void
service_mapper_init ( void )
{
pthread_t tid;
TAILQ_INIT(&service_mapper_queue);
pthread_cond_init(&service_mapper_cond, NULL);
tvhthread_create(&tid, NULL, service_mapper_thread, NULL, 1);
tvhthread_create(&service_mapper_tid, NULL, service_mapper_thread, NULL, 0);
}
void
service_mapper_done ( void )
{
pthread_cond_signal(&service_mapper_cond);
pthread_join(service_mapper_tid, NULL);
}
/*
@ -289,7 +297,7 @@ service_mapper_thread ( void *aux )
pthread_mutex_lock(&global_lock);
while (1) {
while (tvheadend_running) {
/* Wait for work */
while (!(s = TAILQ_FIRST(&service_mapper_queue))) {
@ -298,7 +306,11 @@ service_mapper_thread ( void *aux )
tvhinfo("service_mapper", "idle");
}
pthread_cond_wait(&service_mapper_cond, &global_lock);
if (!tvheadend_running)
break;
}
if (!tvheadend_running)
break;
service_mapper_remove(s);
if (!working) {
@ -327,11 +339,17 @@ service_mapper_thread ( void *aux )
/* Wait */
run = 1;
pthread_mutex_lock(&sq.sq_mutex);
while(run) {
while(tvheadend_running && run) {
/* Wait for message */
while((sm = TAILQ_FIRST(&sq.sq_queue)) == NULL)
while((sm = TAILQ_FIRST(&sq.sq_queue)) == NULL) {
pthread_cond_wait(&sq.sq_cond, &sq.sq_mutex);
if (!tvheadend_running)
break;
}
if (!tvheadend_running)
break;
TAILQ_REMOVE(&sq.sq_queue, sm, sm_link);
pthread_mutex_unlock(&sq.sq_mutex);
@ -353,6 +371,8 @@ service_mapper_thread ( void *aux )
streaming_msg_free(sm);
pthread_mutex_lock(&sq.sq_mutex);
}
if (!tvheadend_running)
break;
streaming_queue_clear(&sq.sq_queue);
pthread_mutex_unlock(&sq.sq_mutex);
@ -370,5 +390,7 @@ service_mapper_thread ( void *aux )
service_mapper_stat.active = NULL;
api_service_mapper_notify();
}
pthread_mutex_unlock(&global_lock);
return NULL;
}

View file

@ -37,6 +37,7 @@ typedef struct service_mapper_status
} service_mapper_status_t;
void service_mapper_init ( void );
void service_mapper_done ( void );
// Start new mapping
void service_mapper_start

View file

@ -77,6 +77,15 @@ hts_settings_init(const char *confpath)
}
}
/**
*
*/
void
hts_settings_done(void)
{
free(settingspath);
}
/**
*
*/

View file

@ -24,6 +24,8 @@
void hts_settings_init(const char *confpath);
void hts_settings_done(void);
void hts_settings_save(htsmsg_t *record, const char *pathfmt, ...);
htsmsg_t *hts_settings_load(const char *pathfmt, ...);

View file

@ -403,6 +403,9 @@ subscription_unsubscribe(th_subscription_t *s)
if(s->ths_start_message != NULL)
streaming_msg_free(s->ths_start_message);
if(s->ths_output->st_cb == subscription_input_null)
free(s->ths_output);
free(s->ths_title);
free(s->ths_hostname);
@ -754,6 +757,20 @@ subscription_init(void)
subscription_status_callback(NULL);
}
/**
* Shutdown subsystem
*/
void
subscription_done(void)
{
th_subscription_t *s;
pthread_mutex_lock(&global_lock);
while ((s = LIST_FIRST(&subscriptions)) != NULL)
subscription_unsubscribe(s);
pthread_mutex_unlock(&global_lock);
}
/* **************************************************************************
* Subscription control
* *************************************************************************/

View file

@ -100,6 +100,8 @@ typedef struct th_subscription {
*/
void subscription_init(void);
void subscription_done(void);
void subscription_unsubscribe(th_subscription_t *s);
void subscription_set_weight(th_subscription_t *s, unsigned int weight);

View file

@ -29,6 +29,7 @@
#include <stdarg.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
@ -40,6 +41,8 @@
#include "notify.h"
int tcp_preferred_address_family = AF_INET;
int tcp_server_running;
th_pipe_t tcp_server_pipe;
/**
*
@ -330,6 +333,11 @@ tcp_read_timeout(int fd, void *buf, size_t len, int timeout)
x = poll(&fds, 1, timeout);
if(x == 0)
return ETIMEDOUT;
if(x == -1) {
if (errno == EAGAIN)
continue;
return errno;
}
x = recv(fd, buf + tot, len - tot, MSG_DONTWAIT);
if(x == -1) {
@ -385,6 +393,7 @@ typedef struct tcp_server {
} tcp_server_t;
typedef struct tcp_server_launch {
pthread_t tid;
int fd;
tcp_server_ops_t ops;
void *opaque;
@ -392,9 +401,11 @@ typedef struct tcp_server_launch {
struct sockaddr_storage self;
time_t started;
LIST_ENTRY(tcp_server_launch) link;
LIST_ENTRY(tcp_server_launch) alink;
} tcp_server_launch_t;
static LIST_HEAD(, tcp_server_launch) tcp_server_launches = { 0 };
static LIST_HEAD(, tcp_server_launch) tcp_server_active = { 0 };
/**
*
@ -448,6 +459,7 @@ tcp_server_start(void *aux)
LIST_REMOVE(tsl, link);
notify_reload("connections");
}
LIST_REMOVE(tsl, alink);
pthread_mutex_unlock(&global_lock);
free(tsl);
@ -465,14 +477,9 @@ tcp_server_loop(void *aux)
tvhpoll_event_t ev;
tcp_server_t *ts;
tcp_server_launch_t *tsl;
pthread_attr_t attr;
pthread_t tid;
socklen_t slen;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
while(1) {
while(tcp_server_running) {
r = tvhpoll_wait(tcp_server_poll, &ev, 1, -1);
if(r == -1) {
perror("tcp_server: tvhpoll_wait");
@ -482,6 +489,8 @@ tcp_server_loop(void *aux)
if (r == 0) continue;
ts = ev.data.ptr;
if (ts == (tcp_server_t *)&tcp_server_pipe)
break;
if(ev.events & TVHPOLL_HUP) {
close(ts->serverfd);
@ -511,9 +520,13 @@ tcp_server_loop(void *aux)
continue;
}
tvhthread_create(&tid, &attr, tcp_server_start, tsl, 1);
pthread_mutex_lock(&global_lock);
LIST_INSERT_HEAD(&tcp_server_active, tsl, alink);
pthread_mutex_unlock(&global_lock);
tvhthread_create(&tsl->tid, NULL, tcp_server_start, tsl, 0);
}
}
tvhtrace("tcp", "server thread finished");
return NULL;
}
@ -600,6 +613,23 @@ tcp_server_create
return ts;
}
/**
*
*/
void
tcp_server_delete(void *server)
{
tcp_server_t *ts = server;
tvhpoll_event_t ev;
memset(&ev, 0, sizeof(ev));
ev.fd = ts->serverfd;
ev.events = TVHPOLL_IN;
ev.data.ptr = ts;
tvhpoll_rem(tcp_server_poll, &ev, 1);
free(ts);
}
/*
* Connections status
*/
@ -635,14 +665,58 @@ tcp_server_connections ( void )
/**
*
*/
pthread_t tcp_server_tid;
void
tcp_server_init(int opt_ipv6)
{
pthread_t tid;
tvhpoll_event_t ev;
if(opt_ipv6)
tcp_preferred_address_family = AF_INET6;
tvh_pipe(O_NONBLOCK, &tcp_server_pipe);
tcp_server_poll = tvhpoll_create(10);
tvhthread_create(&tid, NULL, tcp_server_loop, NULL, 1);
memset(&ev, 0, sizeof(ev));
ev.fd = tcp_server_pipe.rd;
ev.events = TVHPOLL_IN;
ev.data.ptr = &tcp_server_pipe;
tvhpoll_add(tcp_server_poll, &ev, 1);
tcp_server_running = 1;
tvhthread_create(&tcp_server_tid, NULL, tcp_server_loop, NULL, 0);
}
void
tcp_server_done(void)
{
pthread_t tid;
tcp_server_launch_t *tsl;
char c = 'E';
tcp_server_running = 0;
tvh_write(tcp_server_pipe.wr, &c, 1);
pthread_mutex_lock(&global_lock);
LIST_FOREACH(tsl, &tcp_server_active, alink) {
if (tsl->ops.cancel)
tsl->ops.cancel(tsl->opaque);
close(tsl->fd);
tsl->fd = -1;
pthread_kill(tsl->tid, SIGTERM);
}
pthread_mutex_unlock(&global_lock);
pthread_join(tcp_server_tid, NULL);
tvh_pipe_close(&tcp_server_pipe);
tvhpoll_destroy(tcp_server_poll);
pthread_mutex_lock(&global_lock);
while ((tsl = LIST_FIRST(&tcp_server_active)) != NULL) {
tid = tsl->tid;
pthread_mutex_unlock(&global_lock);
pthread_join(tid, NULL);
pthread_mutex_lock(&global_lock);
}
pthread_mutex_unlock(&global_lock);
}

View file

@ -29,11 +29,13 @@ typedef struct tcp_server_ops
struct sockaddr_storage *self);
void (*stop) (void *opaque);
void (*status) (void *opaque, htsmsg_t *m);
void (*cancel) (void *opaque);
} tcp_server_ops_t;
extern int tcp_preferred_address_family;
void tcp_server_init(int opt_ipv6);
void tcp_server_done(void);
int tcp_connect(const char *hostname, int port, char *errbuf,
size_t errbufsize, int timeout);
@ -45,6 +47,8 @@ typedef void (tcp_server_callback_t)(int fd, void *opaque,
void *tcp_server_create(const char *bindaddr, int port,
tcp_server_ops_t *ops, void *opaque);
void tcp_server_delete(void *server);
int tcp_read(int fd, void *buf, size_t len);
char *tcp_read_line(int fd, htsbuf_queue_t *spill);

View file

@ -70,6 +70,8 @@ static inline htsmsg_t *tvheadend_capabilities_list(int check)
#define PTS_UNSET INT64_C(0x8000000000000000)
extern int tvheadend_running;
extern pthread_mutex_t global_lock;
extern pthread_mutex_t ffmpeg_lock;
extern pthread_mutex_t fork_lock;
@ -540,6 +542,8 @@ static inline void mystrset(char **p, const char *s)
*p = s ? strdup(s) : NULL;
}
void doexit(int x);
int tvhthread_create0
(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg,
@ -604,6 +608,11 @@ int rmtree ( const char *path );
char *regexp_escape ( const char *str );
#define SKEL_DECLARE(name, type) type *name;
#define SKEL_ALLOC(name) do { if (!name) name = calloc(1, sizeof(*name)); } while (0)
#define SKEL_USED(name) do { name = NULL; } while (0)
#define SKEL_FREE(name) do { free(name); name = NULL; } while (0)
/* glibc wrapper */
#if ! ENABLE_QSORT_R
void

View file

@ -224,7 +224,7 @@ tvhlog_thread ( void *p )
/* Wait */
if (!(msg = TAILQ_FIRST(&tvhlog_queue))) {
if (tvhlog_run != 1) break;
if (!tvhlog_run) break;
if (fp) {
fclose(fp); // only issue here is we close with mutex!
// but overall performance will be higher
@ -233,6 +233,7 @@ tvhlog_thread ( void *p )
pthread_cond_wait(&tvhlog_cond, &tvhlog_mutex);
continue;
}
if (!msg) break;
TAILQ_REMOVE(&tvhlog_queue, msg, link);
tvhlog_queue_size--;
if (tvhlog_queue_size < (TVHLOG_QUEUE_MAXSIZE / 2))
@ -252,7 +253,9 @@ tvhlog_thread ( void *p )
tvhlog_process(msg, options, &fp, path);
pthread_mutex_lock(&tvhlog_mutex);
}
if (fp)
fclose(fp);
pthread_mutex_unlock(&tvhlog_mutex);
return NULL;
}
@ -420,15 +423,18 @@ void
tvhlog_start ( void )
{
tvhlog_run = 1;
tvhthread_create(&tvhlog_tid, NULL, tvhlog_thread, NULL, 1);
tvhthread_create(&tvhlog_tid, NULL, tvhlog_thread, NULL, 0);
}
void
tvhlog_end ( void )
{
pthread_mutex_lock(&tvhlog_mutex);
tvhlog_run = 2;
tvhlog_run = 0;
pthread_cond_signal(&tvhlog_cond);
pthread_mutex_unlock(&tvhlog_mutex);
pthread_join(tvhlog_tid, NULL);
free(tvhlog_path);
htsmsg_destroy(tvhlog_debug);
htsmsg_destroy(tvhlog_trace);
}

View file

@ -86,6 +86,12 @@ void _tvhlog_hexdump ( const char *file, int line,
#define tvhlog_hexdump(...) (void)0
#endif
#define tvhftrace(subsys, fcn) do { \
tvhtrace(subsys, "%s() enter", #fcn); \
fcn(); \
tvhtrace(subsys, "%s() leave", #fcn); \
} while (0)
#define tvhdebug(...) tvhlog(LOG_DEBUG, ##__VA_ARGS__)
#define tvhinfo(...) tvhlog(LOG_INFO, ##__VA_ARGS__)
#define tvhwarn(...) tvhlog(LOG_WARNING, ##__VA_ARGS__)

View file

@ -48,6 +48,7 @@ static pthread_cond_t comet_cond = PTHREAD_COND_INITIALIZER;
static LIST_HEAD(, comet_mailbox) mailboxes;
int mailbox_tally;
int comet_running;
typedef struct comet_mailbox {
char *cmb_boxid; /* SHA-1 hash */
@ -198,6 +199,10 @@ comet_mailbox_poll(http_connection_t *hc, const char *remain, void *opaque)
usleep(100000); /* Always sleep 0.1 sec to avoid comet storms */
pthread_mutex_lock(&comet_mutex);
if (!comet_running) {
pthread_mutex_unlock(&comet_mutex);
return 400;
}
if(cometid != NULL)
LIST_FOREACH(cmb, &mailboxes, cmb_link)
@ -216,8 +221,13 @@ comet_mailbox_poll(http_connection_t *hc, const char *remain, void *opaque)
cmb->cmb_last_used = 0; /* Make sure we're not flushed out */
if(!im && cmb->cmb_messages == NULL)
if(!im && cmb->cmb_messages == NULL) {
pthread_cond_timedwait(&comet_cond, &comet_mutex, &ts);
if (!comet_running) {
pthread_mutex_unlock(&comet_mutex);
return 400;
}
}
m = htsmsg_create_map();
htsmsg_add_str(m, "boxid", cmb->cmb_boxid);
@ -279,10 +289,24 @@ comet_mailbox_dbg(http_connection_t *hc, const char *remain, void *opaque)
void
comet_init(void)
{
pthread_mutex_lock(&comet_mutex);
comet_running = 1;
pthread_mutex_unlock(&comet_mutex);
http_path_add("/comet/poll", NULL, comet_mailbox_poll, ACCESS_WEB_INTERFACE);
http_path_add("/comet/debug", NULL, comet_mailbox_dbg, ACCESS_WEB_INTERFACE);
}
void
comet_done(void)
{
comet_mailbox_t *cmb;
pthread_mutex_lock(&comet_mutex);
comet_running = 0;
while ((cmb = LIST_FIRST(&mailboxes)) != NULL)
cmb_destroy(cmb);
pthread_mutex_unlock(&comet_mutex);
}
/**
*
@ -294,14 +318,16 @@ comet_mailbox_add_message(htsmsg_t *m, int isdebug)
pthread_mutex_lock(&comet_mutex);
LIST_FOREACH(cmb, &mailboxes, cmb_link) {
if (comet_running) {
LIST_FOREACH(cmb, &mailboxes, cmb_link) {
if(isdebug && !cmb->cmb_debug)
continue;
if(isdebug && !cmb->cmb_debug)
continue;
if(cmb->cmb_messages == NULL)
cmb->cmb_messages = htsmsg_create_list();
htsmsg_add_msg(cmb->cmb_messages, NULL, htsmsg_copy(m));
if(cmb->cmb_messages == NULL)
cmb->cmb_messages = htsmsg_create_list();
htsmsg_add_msg(cmb->cmb_messages, NULL, htsmsg_copy(m));
}
}
pthread_cond_broadcast(&comet_cond);

View file

@ -1360,7 +1360,7 @@ extjs_service_delete(htsmsg_t *in)
TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
if((id = htsmsg_field_get_string(f)) != NULL &&
(t = service_find_by_identifier(id)) != NULL)
service_destroy(t);
service_destroy(t, 1);
}
}

View file

@ -484,7 +484,7 @@ page_epgsave(http_connection_t *hc,
"<epgflush>1</epgflush>\n");
pthread_mutex_lock(&global_lock);
epg_save(NULL);
epg_save();
pthread_mutex_unlock(&global_lock);
http_output_content(hc, "text/xml");

View file

@ -241,7 +241,7 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq,
tp.tv_usec = 0;
setsockopt(hc->hc_fd, SOL_SOCKET, SO_SNDTIMEO, &tp, sizeof(tp));
while(run) {
while(run && tvheadend_running) {
pthread_mutex_lock(&sq->sq_mutex);
sm = TAILQ_FIRST(&sq->sq_queue);
if(sm == NULL) {
@ -1081,7 +1081,7 @@ page_imagecache(http_connection_t *hc, const char *remain, void *opaque)
static void
webui_static_content(const char *http_path, const char *source)
{
http_path_add(http_path, strdup(source), page_static_file,
http_path_add(http_path, (void *)source, page_static_file,
ACCESS_WEB_INTERFACE);
}
@ -1130,3 +1130,9 @@ webui_init(void)
webui_api_init();
}
void
webui_done(void)
{
comet_done();
}

View file

@ -24,6 +24,7 @@
#include "http.h"
void webui_init(void);
void webui_done(void);
void simpleui_start(void);
@ -54,6 +55,8 @@ void webui_api_init ( void );
*/
void comet_init(void);
void comet_done(void);
void comet_mailbox_add_message(htsmsg_t *m, int isdebug);
void comet_flush(void);

View file

@ -4,6 +4,7 @@
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#ifdef PLATFORM_LINUX
@ -100,6 +101,7 @@ static void *
thread_wrapper ( void *p )
{
struct thread_state *ts = p;
sigset_t set;
#if defined(PLATFORM_LINUX)
/* Set name */
@ -109,6 +111,12 @@ thread_wrapper ( void *p )
pthread_set_name_np(pthread_self(), ts->name);
#endif
sigemptyset(&set);
sigaddset(&set, SIGTERM);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
signal(SIGTERM, doexit);
/* Run */
tvhdebug("thread", "created thread %ld [%s / %p(%p)]",
(long)pthread_self(), ts->name, ts->run, ts->arg);