From: Jaroslav Kysela Date: Tue, 8 Mar 2016 11:41:29 +0000 (+0100) Subject: scanfile: cleanups, allow runtime update, fixes #3612 X-Git-Tag: v4.2.1~941 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=95fcfc265984b553aec1089f5bb90b36c8c523d2;p=thirdparty%2Ftvheadend.git scanfile: cleanups, allow runtime update, fixes #3612 The scanfiles are parsed in the tasklet thread now, so it might also improve the start time. --- diff --git a/src/api/api_mpegts.c b/src/api/api_mpegts.c index ea54ad0b4..eee1f13d0 100644 --- a/src/api/api_mpegts.c +++ b/src/api/api_mpegts.c @@ -381,29 +381,18 @@ api_dvb_scanfile_list if (!type) return -EINVAL; - if (!strcasecmp(type, "dvbt")) - list = &scanfile_regions_DVBT; - else if (!strcasecmp(type, "dvbc")) - list = &scanfile_regions_DVBC; - else if (!strcasecmp(type, "dvbs")) - list = &scanfile_regions_DVBS; - else if (!strcasecmp(type, "atsc-t")) - list = &scanfile_regions_ATSC_T; - else if (!strcasecmp(type, "atsc-c")) - list = &scanfile_regions_ATSC_C; - else if (!strcasecmp(type, "isdb-t")) - list = &scanfile_regions_ISDB_T; - else + list = scanfile_find_region_list(type); + if (!list) return -EINVAL; l = htsmsg_create_list(); - LIST_FOREACH(r, list, sfr_link) { + LIST_FOREACH(r, &list->srl_regions, sfr_link) { LIST_FOREACH(n, &r->sfr_networks, sfn_link) { if (satpos != INT_MAX && n->sfn_satpos != satpos) continue; e = htsmsg_create_map(); sprintf(buf, "%s/%s/%s", type, r->sfr_id, n->sfn_id); htsmsg_add_str(e, "key", buf); - if (list != &scanfile_regions_DVBS) { + if (strcmp(list->srl_type, "dvb-s")) { sprintf(buf, "%s: %s", r->sfr_name, n->sfn_name); htsmsg_add_str(e, "val", buf); } else { diff --git a/src/config.c b/src/config.c index b1a716249..99408c3d9 100644 --- a/src/config.c +++ b/src/config.c @@ -33,6 +33,7 @@ #include "url.h" #include "satip/server.h" #include "channels.h" +#include "input/mpegts/scanfile.h" #include @@ -1930,6 +1931,29 @@ config_class_piconscheme_list ( void *o, const char *lang ) return strtab2htsmsg(tab, 1, lang); } +#if ENABLE_MPEGTS_DVB +static void +config_muxconfpath_notify_cb(void *opaque, int disarmed) +{ + char *muxconf_path = opaque; + if (disarmed || muxconf_path == NULL || muxconf_path[0] == '\0') { + free(muxconf_path); + return; + } + tvhinfo("config", "scanfile re-initialization with path %s", muxconf_path); + scanfile_init(muxconf_path, 1); + free(muxconf_path); +} +#endif + +static void +config_muxconfpath_notify ( void *o, const char *lang ) +{ +#if ENABLE_MPEGTS_DVB + tasklet_arm_alloc(config_muxconfpath_notify_cb, strdup(config.muxconf_path)); +#endif +} + const idclass_t config_class = { .ic_snode = &config.idnode, .ic_class = "config", @@ -2142,6 +2166,7 @@ const idclass_t config_class = { "/usr/share/dvb/. Leave blank to use Tvheadend's " "internal file set."), .off = offsetof(config_t, muxconf_path), + .notify = config_muxconfpath_notify, .opts = PO_ADVANCED, .group = 4 }, diff --git a/src/input/mpegts/mpegts_network_dvb.c b/src/input/mpegts/mpegts_network_dvb.c index 3472d47ac..47fa55842 100644 --- a/src/input/mpegts/mpegts_network_dvb.c +++ b/src/input/mpegts/mpegts_network_dvb.c @@ -24,6 +24,7 @@ #include "mpegts_dvb.h" #include "linuxdvb/linuxdvb_private.h" #include "dvb_charset.h" +#include "config.h" #include "scanfile.h" #include @@ -843,9 +844,6 @@ void dvb_network_init ( void ) const char *s; int i; - /* Load scan files */ - scanfile_init(); - /* Load list of mux charset global overrides */ dvb_charset_init(); diff --git a/src/input/mpegts/scanfile.c b/src/input/mpegts/scanfile.c index 4213d1a5d..703d52133 100644 --- a/src/input/mpegts/scanfile.c +++ b/src/input/mpegts/scanfile.c @@ -34,12 +34,23 @@ #include #include -scanfile_region_list_t scanfile_regions_DVBC; -scanfile_region_list_t scanfile_regions_DVBT; -scanfile_region_list_t scanfile_regions_DVBS; -scanfile_region_list_t scanfile_regions_ATSC_T; -scanfile_region_list_t scanfile_regions_ATSC_C; -scanfile_region_list_t scanfile_regions_ISDB_T; +#define SCANFILE_LIMIT (4*1024*1024) + +static const char *scanfile_region_types[][2] = { + { "dvb-s", "dvbs" }, + { "dvb-t", "dvbt" }, + { "dvb-c", "dvbc" }, + { "atsc-t", NULL }, + { "atsc-c", NULL }, + { "isdb-t", NULL } +}; + +#define REGIONS ARRAY_SIZE(scanfile_region_types) + +static scanfile_region_list_t *scanfile_regions; +static scanfile_region_list_t *scanfile_regions_load; +static int64_t scanfile_total_load; + /* ************************************************************************** * Country codes @@ -281,15 +292,15 @@ scanfile_region_create { scanfile_region_t *reg; scanfile_region_list_t *list = NULL; - if (!strcmp(type, "dvb-s")) list = &scanfile_regions_DVBS; - else if (!strcmp(type, "dvb-t")) list = &scanfile_regions_DVBT; - else if (!strcmp(type, "dvb-c")) list = &scanfile_regions_DVBC; - else if (!strcmp(type, "atsc-t")) list = &scanfile_regions_ATSC_T; - else if (!strcmp(type, "atsc-c")) list = &scanfile_regions_ATSC_C; - else if (!strcmp(type, "isdb-t")) list = &scanfile_regions_ISDB_T; + int i; + for (i = 0; i < REGIONS; i++) + if (strcmp(scanfile_regions_load[i].srl_type, type) == 0) { + list = &scanfile_regions_load[i]; + break; + } if (!list) return NULL; - LIST_FOREACH(reg, list, sfr_link) { + LIST_FOREACH(reg, &list->srl_regions, sfr_link) { if (!strcmp(reg->sfr_id, id)) break; } @@ -298,7 +309,7 @@ scanfile_region_create reg = calloc(1, sizeof(scanfile_region_t)); reg->sfr_id = strdup(id); reg->sfr_name = strdup(desc); - LIST_INSERT_SORTED(list, reg, sfr_link, scanfile_region_cmp); + LIST_INSERT_SORTED(&list->srl_regions, reg, sfr_link, scanfile_region_cmp); } return reg; @@ -700,8 +711,11 @@ scanfile_load_file tvhtrace("scanfile", "load file %s", name); + if (scanfile_total_load > SCANFILE_LIMIT) return; fp = fb_open2(dir, name, 1, 0); if (!fp) return; + scanfile_total_load += fb_size(fp); + if (scanfile_total_load > SCANFILE_LIMIT) goto end; /* Process file */ load = 1; @@ -734,6 +748,7 @@ scanfile_load_file break; } } +end: fb_close(fp); } @@ -778,7 +793,7 @@ scanfile_stats(const char *what, scanfile_region_list_t *list) scanfile_network_t *sfn; int regions = 0, networks =0; - LIST_FOREACH(reg, list, sfr_link) { + LIST_FOREACH(reg, &list->srl_regions, sfr_link) { regions++; LIST_FOREACH(sfn, ®->sfr_networks, sfn_link) networks++; @@ -790,14 +805,43 @@ scanfile_stats(const char *what, scanfile_region_list_t *list) return 0; } +/* + * Destroy the region + */ +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->srl_regions)) != NULL) { + LIST_REMOVE(reg, sfr_link); + while ((net = LIST_FIRST(®->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); + } +} + /* * Initialise the mux list */ void -scanfile_init ( void ) +scanfile_init ( const char *muxconf_path, int lock ) { - const char *path = config.muxconf_path; - int r = 0; + const char *path = muxconf_path; + char buf[32], *p; + int r = 0, i; if (!path || !*path) #if ENABLE_DVBSCAN path = "data/dvb-scan"; @@ -806,59 +850,77 @@ scanfile_init ( void ) #else path = "/usr/share/dvb"; #endif + + scanfile_total_load = 0; + scanfile_regions_load = calloc(REGIONS, sizeof(scanfile_region_list_t)); + for (i = 0; i < REGIONS; i++) { + scanfile_regions_load[i].srl_type = scanfile_region_types[i][0]; + scanfile_regions_load[i].srl_alt_type = scanfile_region_types[i][1]; + } + scanfile_load_dir(path, NULL, 0); - r += scanfile_stats("DVB-T", &scanfile_regions_DVBT); - r += scanfile_stats("DVB-S", &scanfile_regions_DVBS); - r += scanfile_stats("DVB-C", &scanfile_regions_DVBC); - r += scanfile_stats("ATSC-T", &scanfile_regions_ATSC_T); - r += scanfile_stats("ATSC-C", &scanfile_regions_ATSC_C); - r += scanfile_stats("ISDB-T", &scanfile_regions_ISDB_T); + for (i = 0; i < REGIONS; i++) { + snprintf(buf, sizeof(buf)-1, "%s", scanfile_regions_load[i].srl_type); + buf[sizeof(buf)-1] = '\0'; + for (p = buf; *p; p++) *p = toupper(*p); + r += scanfile_stats(buf, &scanfile_regions_load[i]); + } if (!r) { tvhwarn("scanfile", "no predefined muxes found, check path '%s%s'", path[0] == '/' ? path : TVHEADEND_DATADIR "/", path[0] == '/' ? "" : path); tvhwarn("scanfile", "expected tree structure - http://git.linuxtv.org/cgit.cgi/dtv-scan-tables.git/tree/"); + for (i = 0; i < REGIONS; i++) + scanfile_done_region(&scanfile_regions_load[i]); + free(scanfile_regions_load); + scanfile_regions_load = NULL; + } else { + if (lock) + pthread_mutex_lock(&global_lock); + scanfile_done(); + scanfile_regions = scanfile_regions_load; + scanfile_regions_load = NULL; + if (lock) + pthread_mutex_unlock(&global_lock); } } /* * Destroy the mux list */ -static void -scanfile_done_region( scanfile_region_list_t *list ) +void +scanfile_done ( void ) { - scanfile_region_t *reg; - scanfile_network_t *net; - dvb_mux_conf_t *mux; + scanfile_region_list_t *l; + int i; - while ((reg = LIST_FIRST(list)) != NULL) { - LIST_REMOVE(reg, sfr_link); - while ((net = LIST_FIRST(®->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); + l = scanfile_regions; + scanfile_regions = NULL; + if (l) { + for (i = 0; i < REGIONS; i++) + scanfile_done_region(&l[i]); + free(l); } } -void -scanfile_done ( void ) +/* + * Find region list by type + */ +scanfile_region_list_t * +scanfile_find_region_list ( const char *type ) { - scanfile_done_region(&scanfile_regions_DVBS); - scanfile_done_region(&scanfile_regions_DVBT); - scanfile_done_region(&scanfile_regions_DVBC); - scanfile_done_region(&scanfile_regions_ATSC_T); - scanfile_done_region(&scanfile_regions_ATSC_C); - scanfile_done_region(&scanfile_regions_ISDB_T); + scanfile_region_list_t *list = NULL; + int i; + if (scanfile_regions == NULL) + return NULL; + for (i = 0; i < REGIONS; i++) + if (strcasecmp(scanfile_regions[i].srl_type, type) == 0 || + strcasecmp(scanfile_regions[i].srl_alt_type, type) == 0) { + list = &scanfile_regions[i]; + break; + } + return list; } /* @@ -876,25 +938,14 @@ scanfile_find ( const char *id ) /* Type */ if (!(tok = strtok_r(tmp, "/", &s))) goto fail; - if (!strcasecmp(tok, "dvbt")) - l = &scanfile_regions_DVBT; - else if (!strcasecmp(tok, "dvbc")) - l = &scanfile_regions_DVBC; - else if (!strcasecmp(tok, "dvbs")) - l = &scanfile_regions_DVBS; - else if (!strcasecmp(tok, "atsc-t")) - l = &scanfile_regions_ATSC_T; - else if (!strcasecmp(tok, "atsc-c")) - l = &scanfile_regions_ATSC_C; - else if (!strcasecmp(tok, "isdb-t")) - l = &scanfile_regions_ISDB_T; - else + l = scanfile_find_region_list(tok); + if (!l) goto fail; /* Region */ if (!(tok = strtok_r(NULL, "/", &s))) goto fail; - LIST_FOREACH(r, l, sfr_link) + LIST_FOREACH(r, &l->srl_regions, sfr_link) if (!strcmp(r->sfr_id, tok)) break; if (!r) goto fail; diff --git a/src/input/mpegts/scanfile.h b/src/input/mpegts/scanfile.h index 02231a2ce..817d2e15a 100644 --- a/src/input/mpegts/scanfile.h +++ b/src/input/mpegts/scanfile.h @@ -34,17 +34,16 @@ typedef struct scanfile_region { LIST_HEAD(,scanfile_network) sfr_networks; } scanfile_region_t; -typedef LIST_HEAD(,scanfile_region) scanfile_region_list_t; -extern scanfile_region_list_t scanfile_regions_DVBC; -extern scanfile_region_list_t scanfile_regions_DVBT; -extern scanfile_region_list_t scanfile_regions_DVBS; -extern scanfile_region_list_t scanfile_regions_ATSC_T; -extern scanfile_region_list_t scanfile_regions_ATSC_C; -extern scanfile_region_list_t scanfile_regions_ISDB_T; +typedef struct scanfile_region_list { + LIST_HEAD(,scanfile_region) srl_regions; + const char *srl_type; + const char *srl_alt_type; +} scanfile_region_list_t; -void scanfile_init ( void ); +void scanfile_init ( const char *muxconf_path, int lock ); void scanfile_done ( void ); +scanfile_region_list_t *scanfile_find_region_list ( const char *type ); scanfile_network_t *scanfile_find ( const char *id ); #endif /* __DVB_SCANFILES_H__ */