]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
scanfile: cleanups, allow runtime update, fixes #3612
authorJaroslav Kysela <perex@perex.cz>
Tue, 8 Mar 2016 11:41:29 +0000 (12:41 +0100)
committerJaroslav Kysela <perex@perex.cz>
Tue, 8 Mar 2016 11:41:32 +0000 (12:41 +0100)
The scanfiles are parsed in the tasklet thread now, so it might
also improve the start time.

src/api/api_mpegts.c
src/config.c
src/input/mpegts/mpegts_network_dvb.c
src/input/mpegts/scanfile.c
src/input/mpegts/scanfile.h

index ea54ad0b4deff7add67c3fd211cafe34623b7efb..eee1f13d0001e76f698c425f628cbe1d54e58e5b 100644 (file)
@@ -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 {
index b1a7162490886d204156015e4e716268157e6899..99408c3d923d9123112c29f961a23f0d4f3a3c56 100644 (file)
@@ -33,6 +33,7 @@
 #include "url.h"
 #include "satip/server.h"
 #include "channels.h"
+#include "input/mpegts/scanfile.h"
 
 #include <netinet/ip.h>
 
@@ -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
     },
index 3472d47ac331f8be5f995b6037f401531ed0c1ca..47fa558423ebaaff0fd4a0843e53c58f01c1330e 100644 (file)
@@ -24,6 +24,7 @@
 #include "mpegts_dvb.h"
 #include "linuxdvb/linuxdvb_private.h"
 #include "dvb_charset.h"
+#include "config.h"
 #include "scanfile.h"
 
 #include <sys/types.h>
@@ -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();
 
index 4213d1a5dddd802a6d6c005cf53e0e5915ae3be7..703d52133ec73cbc7bf9e385c7e8d26dde680389 100644 (file)
 #include <strings.h>
 #include <ctype.h>
 
-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, &reg->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(&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);
+  }
+}
+
 /*
  * 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(&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);
+  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;
index 02231a2cea94af952058eee77f9f0b67d3c2b54b..817d2e15a84f7492e2a4737a00863e8fd5cb6b5e 100644 (file)
@@ -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__ */