]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Graceful exit
authorJaroslav Kysela <perex@perex.cz>
Mon, 17 Feb 2014 10:43:01 +0000 (11:43 +0100)
committerJaroslav Kysela <perex@perex.cz>
Mon, 17 Feb 2014 12:13:14 +0000 (13:13 +0100)
It's necessary to do serious checks for the memory leaks using
tools like valgrind. This patch tries to implement a graceful
exit for all tvheadend components and free allocated memory.

Also, some memory leaks were fixed.

93 files changed:
src/access.c
src/access.h
src/api.c
src/api.h
src/api/api_idnode.c
src/avahi.c
src/avahi.h
src/channels.c
src/channels.h
src/config2.c
src/config2.h
src/descrambler.h
src/descrambler/capmt.c
src/descrambler/capmt.h
src/descrambler/cwc.c
src/descrambler/cwc.h
src/descrambler/descrambler.c
src/dtable.c
src/dtable.h
src/dvr/dvr.h
src/dvr/dvr_autorec.c
src/dvr/dvr_db.c
src/dvr/dvr_inotify.c
src/epg.c
src/epg.h
src/epgdb.c
src/epggrab.c
src/epggrab.h
src/epggrab/module.c
src/epggrab/module/eit.c
src/epggrab/module/opentv.c
src/epggrab/otamux.c
src/epggrab/private.h
src/fsmonitor.c
src/fsmonitor.h
src/htsp_server.c
src/htsp_server.h
src/http.c
src/http.h
src/http/http_client.c
src/idnode.c
src/idnode.h
src/imagecache.c
src/imagecache.h
src/input/mpegts.h
src/input/mpegts/dvb.h
src/input/mpegts/dvb_charset.c
src/input/mpegts/dvb_charset.h
src/input/mpegts/dvb_psi.c
src/input/mpegts/dvb_support.c
src/input/mpegts/iptv.h
src/input/mpegts/iptv/iptv.c
src/input/mpegts/iptv/iptv_mux.c
src/input/mpegts/iptv/iptv_private.h
src/input/mpegts/linuxdvb.h
src/input/mpegts/linuxdvb/linuxdvb.c
src/input/mpegts/linuxdvb/linuxdvb_adapter.c
src/input/mpegts/linuxdvb/linuxdvb_frontend.c
src/input/mpegts/linuxdvb/linuxdvb_mux.c
src/input/mpegts/linuxdvb/linuxdvb_network.c
src/input/mpegts/linuxdvb/linuxdvb_private.h
src/input/mpegts/linuxdvb/linuxdvb_satconf.c
src/input/mpegts/linuxdvb/scanfile.c
src/input/mpegts/linuxdvb/scanfile.h
src/input/mpegts/mpegts_input.c
src/input/mpegts/mpegts_mux.c
src/input/mpegts/mpegts_network.c
src/input/mpegts/mpegts_service.c
src/input/mpegts/tsfile/tsfile_input.c
src/lang_codes.c
src/lang_codes.h
src/lang_str.c
src/lang_str.h
src/main.c
src/service.c
src/service.h
src/service_mapper.c
src/service_mapper.h
src/settings.c
src/settings.h
src/subscriptions.c
src/subscriptions.h
src/tcp.c
src/tcp.h
src/tvheadend.h
src/tvhlog.c
src/tvhlog.h
src/webui/comet.c
src/webui/extjs.c
src/webui/simpleui.c
src/webui/webui.c
src/webui/webui.h
src/wrappers.c

index 19d8eef6380b1f3769d1260a8511e46d4e27bc8b..443dfd032fae92584f6d357f2c72303b2285e753 100644 (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);
+}
index 2edb0ab903d2f7acbd2c0f79d06b8cc34cb4c725..e1db01ab31a7b668d5ead2a1619b24cf58d2bf88 100644 (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_ */
index 7db5fa1d678607a0b8db34c99b9e84257148859d..97546982c4639113246ada6de832a5907a60abf2 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -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);
+}
index c22abe8b4e2b04fc062a1f7e9314263b0d9d6f79..629330e8187d08bfca25526ee1762d6839af8a67 100644 (file)
--- a/src/api.h
+++ b/src/api.h
@@ -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 );
index 26319e32cbec367fa084962c51e79d6272498afc..e8452ac43b980ec106b1967ed95771c3b0608017 100644 (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);
index c474dd7c3756cb59e4e9916e02bf4700d4abd0d7..e290f818e06ee82edb06b85be13acaafabbf77af 100644 (file)
@@ -54,6 +54,7 @@
 
 static AvahiEntryGroup *group = NULL;
 static char *name = NULL;
+static AvahiSimplePoll *avahi_asp = NULL;
 
 static void create_services(AvahiClient *c);
 
@@ -247,14 +248,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);
 
   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(asp, -1) == 0);
 
   return NULL;
   
@@ -264,10 +264,19 @@ avahi_thread(void *aux)
 /**
  *
  */
+pthread_t avahi_tid;
+
 void
 avahi_init(void)
 {
-  pthread_t tid;
+  avahi_asp = avahi_simple_poll_new();
+  tvhthread_create(&avahi_tid, NULL, avahi_thread, NULL, 0);
+}
 
-  tvhthread_create(&tid, NULL, avahi_thread, NULL, 1);
+void
+avahi_done(void)
+{
+  avahi_simple_poll_quit(avahi_asp);
+  pthread_kill(avahi_tid, SIGTERM);
+  pthread_join(avahi_tid, NULL);
 }
index 891820cdf795bd367ffd83eb02719365748613f8..ca10aa01d03b7e0d45b222dffecc81a6a47e33ac 100644 (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
index 130d3be6d4d8561d3886a0ad14780a82df47c14d..bddce831ed99bf1a7b202e2a98bf74ac24b5b061 100644 (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 *
@@ -540,7 +543,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;
@@ -548,14 +551,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 */
@@ -573,7 +577,8 @@ channel_delete ( channel_t *ch )
   epg_channel_unlink(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);
@@ -619,6 +624,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
  */
@@ -732,15 +752,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)
@@ -878,7 +900,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;
 }
 
@@ -949,3 +971,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");
+}
index 9fa688c57ef5b9ca52f0be9645331e43160c65a3..370ab7c55d89a635d3a3d6fe142265f569af99f1 100644 (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)\
index cfeeb12706a115cbc9e7b4b0d1e63f7e97c9cf68..f22321b1474c5226ece7aa84942b89c9eaf2c442 100644 (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");
index cd68e30621de19e679970fe49ed61f49708c6e60..f090dde1710a64551597f220cdf232a569aa001e 100644 (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 );
index b9ccd50a65fe00bc26dae8ab1db2366ffeea046b..9608db44583ab39f55a35a2bedcaf1ef3ff730fc 100755 (executable)
@@ -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);
index 258bc2bdb7079f7d4d3c1dc14a56bc65f243213d..e317c9c5b8b3e7a6e0bfb9d35ebee55a9563df7c 100644 (file)
@@ -185,6 +185,8 @@ typedef struct capmt {
 
   struct capmt_service_list capmt_services;
 
+  pthread_t capmt_tid;
+
   /* from capmt configuration */
   char *capmt_sockfile;
   char *capmt_hostname;
@@ -1114,7 +1116,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;
@@ -1143,7 +1144,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;
 }
@@ -1281,3 +1282,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");
+}
index 5cbf159a7e15f2d0d67c8bad519e4f49563c9954..711c95d9b0c342062bd9e0f539eb8499e0b7ab07 100644 (file)
@@ -21,6 +21,8 @@
 
 void capmt_init(void);
 
+void capmt_done(void);
+
 void capmt_service_start(struct service *t);
 
 #endif /* CAPMT_H_ */
index 9a068476eb5604f1834105f95d7e6f6886620115..37fa28cc1ec41ccf380f7586f12da242b23a35c3 100755 (executable)
@@ -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>
 
 /*
index 3c28710a733342db7aa8d47a8be6362ebcf52d09..ace3c65716ed3e4410d87becba8d691ffd6c2ae6 100644 (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);
index 8ab6a09820c6fa63abfe0eeb0966e213e9b35718..b466e5681d9fec5dd378f8441482fde98b574698 100755 (executable)
@@ -115,6 +115,13 @@ descrambler_init ( void )
 #endif
 }
 
+void
+descrambler_done ( void )
+{
+  capmt_done();
+  cwc_done();
+}
+
 void
 descrambler_service_start ( service_t *t )
 {
index f86100f117895403583166722fa9929279de379a..f63e75f12d5b105c1e4db5d380e4c8d70eeee2b3 100644 (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);
+  }
+}
+
 /**
  *
  */
index 5a480ac299b820888d64643768e8cd624e71c831..033ccec2f92f216955a3cf421b55c164aaedc077 100644 (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);
index 3e99ca19efec8971c8f9fc8dc692d08ea064bd27..30b19d7b23291496c896e54becf8b7e4e36c6936 100644 (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 );
 
index 52fcef689afe4424b129970aa33719e5eff9fe69..ec92ce3dc7a24f6c52d92498cace79661ca39884 100644 (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);
   }
 
index 545990547ac3a1d288b535b1386ff762071a4c26..e80dae062cad387872df90769f51f95591afd42e 100644 (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:
index db2c64f7658a3c99d50f9f3f08ec3e7b01a950b9..15c80e6b66a1f5366db929205dd95749d6c4fd9a 100644 (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);
index f2a522d616314b74c6ce1c8f25578e5d6cec666e..03322ccde1eab99fb602e251c04e41ea9e73d554 100644 (file)
--- a/src/epg.c
+++ b/src/epg.c
@@ -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;
+}
index f8724e7b7a990b3f21efb3a1816104db6751c7f8..0f17749241c1ec3156c78b809ca8b716123db887 100644 (file)
--- a/src/epg.h
+++ b/src/epg.h
@@ -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);
 
 /* ************************************************************************
index 86cbd6d5fb048200d0cda159a6fbc2af18e01e0d..ec576d3d52ecdbc508e36a0cd73f17a497a760b3 100644 (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);
 
index 7a662c8aad229feb2730c4e91a9f8fa5ffc475ce..33e015b27aecfcaa6fd773d694e056f4d671ee0f 100644 (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();
+}
index 6ab1c02c4a7ce99bebc8607bccfe5fb3947bd475..f7ea7628d0db3aafce7f72c9613fda72a09e5958 100644 (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
index a1112d73acca1b5cfa98a4afe5ab110a8a86e1d7..da0ac173627376d21ec51a3c714d68b2f9368657 100644 (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;
index 65c961d46e161b83b716cc4e252f426d6416a36c..896ce929a9a79c409047ff87e3e2baaf583a67f8 100644 (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);
 }
index 51c4008d79bc93ea02818ab27d7d0e2e5c0acac4..c28650f28f3404239a07ff6063d5ba5e3c6ef124 100644 (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?
index fc90e18f06bcdd8c434e722918f0263a54a2a71c..8beb4451362eabcddb999882598d017c7f0943db 100644 (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
  *
index 50c316979edaee0623dec58e5cd5de13a5c263a7..51940a18b6d6f0dde4c9c66e85f6df5f409422c4 100644 (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 */
index 46a02e09fff61523c4eb4d7aeab514bf9444d608..5881ef251a937384886daa6842f311b11ba39504 100644 (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);
index 8fb3d8caff3646a2e5a09ea6d1fb06dcba2a2ad5..d3c586a973840c7bd4b95a62abb278378665ab49 100644 (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 );
 
index 8a018373aa94d61f22c9e6d97af626535d31b49e..45cccfc4488c24c45f4fd52c18974447aaf47dd5 100644 (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,8 +1987,9 @@ htsp_read_loop(htsp_connection_t *htsp)
 
   /* Session main loop */
 
-  while(1) {
+  while(tvheadend_running) {
 readmsg:
+    tvhlog(LOG_INFO, "htsp", "read_loop");
     if((r = htsp_read_message(htsp, &m, 0)) != 0)
       return r;
 
@@ -2036,6 +2038,7 @@ readmsg:
 
     htsmsg_destroy(m);
   }
+  return 0;
 }
 
 /**
@@ -2052,7 +2055,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 +2216,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 +2235,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
  * *************************************************************************/
index f551ab899bb7f7b43bc933227e14d56a0b47511f..af5f400b06dab32d38a71576f352fddb293c010b 100644 (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);
 
index a01bde42c4fc0e32dd70630e1cf4672863bf959a..4cacf1bf3f3131b7f7fbc07544209683ac1903df 100644 (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);
+}
index acba6240949d03fe4a7b4a1f76abe70d5958aaee..120dda8fa03ec374eb254dd7822a7ccfd4c8b6c4 100644 (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,
index 0448537ead3b14397f32bad21dbe757f57c2614a..e7a0534f944256ad16f64e2b69de598b433a9201 100644 (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 */
index ab27207c86cc9721cd4490fc3c49bb9af1d24875..64ac2c5bcb0690a6db8ce9bc8b52ec23dcc75b69 100644 (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;
 }
index af8f3d17a25b13ba812646e3372a05d5bf98cad2..a10c1056b8f8547082f29ea5fb2403a491b8894f 100644 (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);
index 56a5a87e212da7568a98929acb9b367d6551866d..36202ada01867ba8b0659521c0b77a3a59bbee45 100644 (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
 
 /*
index 39e24a5e9b54c8fecdc53e8fb2b999b2efbd3be4..c5cdc4e6a6c4504ad49f956b940f32d8292b70dc 100644 (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 );
index 6f37f341f089f2459f81745d4a06a1b81d7f46b2..751d5433686f38efb9d142d412c8fddcad04299e 100644 (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
index 62d4ebb0d134e377dbacd30f620c4a8a1945640f..3963efa60af1a571e24b0cf3e77a6c8f234a1cd0 100644 (file)
@@ -276,4 +276,6 @@ int dvb_delsys2type ( enum fe_delivery_system ds );
 
 #endif /* ENABLE_DVBAPI */
 
+void dvb_done       ( void );
+
 #endif /* DVB_SUPPORT_H */
index 9388d6a8f0aad7eeafa0db7784c9047a41055581..d2a30378e118342ff164e2467538584ea8514b30 100644 (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
  */
index 3ef6267a61f4559a4a96e1fe7c11af780188159c..12eedc0743714ed57ff9117bbf75b1fed9883841 100644 (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;
index c6a98c6c1d3c40bc5fe7fbda2fd4c61ea70be3b2..866c264fcd21e52fdb19e3015fbcfd3ab519c1c9 100644 (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);
   }
index 8c9e8d2a782c77482e90220df96621bd5dcbdd34..acba753b785ebdaf975a37ef361cad7da4ee06e3 100644 (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);
+}
index 34cc8b79f6d37e3ac146245c696aa35aafe9141f..83b998d21308c1b1f595a1fe437f606871ea9585 100644 (file)
@@ -21,6 +21,7 @@
 #define __IPTV_H__
 
 void iptv_init ( void );
+void iptv_done ( void );
 
 #endif /* __IPTV_H__ */
 
index 58d6d53d7dafc9a6d12526013bccaac734182e0b..9cc1f729386b4b3adbb9954923c430810d762d9b 100644 (file)
 #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
  *
index c8d99858ca080f0483a8107eaf2ff8b22e792e9f..39b0bc1ff8afb36984df139e4165f99b2649e760 100644 (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
index c0283ce9815b2dccbaed1a7416d6be3d11206d49..bd59c3346d13f94969d13b1c6161893f446459d5 100644 (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 );
 
index a196882f0553579b95f5ee557b0a5f71c4b91590..2bcd38ac0f2bdf8067ff2fb373dc581a50256ea0 100644 (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__ */
index 4c4d5a3a1e4d00d833989a0f6bc0db33689d0b52..e8395fe5c0a3cd9d41557787c2d4ae2799b840ce 100644 (file)
@@ -41,3 +41,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();
+}
index 4ac2f6162c0839a98df0cfd844a6424055a1753f..0ce30af509547c8b974423b9875057d91ac9c6a8 100644 (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;
@@ -267,6 +268,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
       }
     }
@@ -291,6 +293,7 @@ linuxdvb_adapter_add ( const char *path )
     }
 #endif
     pthread_mutex_unlock(&global_lock);
+    htsmsg_destroy(conf);
   }
 
   /* Relock before exit */
@@ -330,6 +333,8 @@ linuxdvb_adapter_del ( const char *path )
     
     /* Delete */
     tvh_hardware_delete((tvh_hardware_t*)la);
+
+    free(la);
   }
 }
 
@@ -420,3 +425,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);
+}
index 908b3f45de3a4552b122f90941ec51d726e397cd..e487ce61fe3ed36d91978e597def882807f8c05f 100644 (file)
@@ -686,7 +686,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;
@@ -904,7 +904,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);
@@ -968,7 +967,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) {
@@ -1024,6 +1023,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);
 
@@ -1037,7 +1038,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);
 }
 
 /******************************************************************************
index 96cfb4243d159ab2db695f48a735d861c5c4e0a1..803c9803ae8e806f411aca980edf62c10362cfbb 100644 (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);
 }
 
 /* **************************************************************************
index 178c7788b6432e8ab0bf9a8e471448675c64471e..3c775226a13c2fbdbcd65b3a12a060ee8919e527 100644 (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
  * ***************************************************************************/
index 12aebdedf9a9a24c51def05dc3b459d309fafece..eb84519a81ef2a4f863218156516e0f217568f6e 100644 (file)
@@ -202,6 +202,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 );
@@ -240,6 +242,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
index 71d5f25953623b60afd7caeb8ef633987ab4e6e5..723a4abee1802b8cffc973eba204a482cd1d7d80 100644 (file)
@@ -1085,7 +1085,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 *
@@ -1160,8 +1160,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);
 }
 
 /******************************************************************************
@@ -1217,6 +1219,7 @@ void
 linuxdvb_diseqc_destroy ( linuxdvb_diseqc_t *ld )
 {
   idnode_unlink(&ld->ld_id);
+  free((void *)ld->ld_type);
 }
 
 int
index dcc342094af692b2fe80ea2ded17094a8a21ddac..2851c0a2c9f1b28915caa5bd57510da0e4ce3f11 100644 (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
  */
index cda2da76fc9cd3d549741c1d18d1f34f3fd0a0e3..ee08a95ccf2d3bef01635f3853d3ff82db1987db 100644 (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 );
   
index ad2a9e53ac4214ee82dc9c5b090b0804d9d12c83..4e85ede670651eea35398f72e898a2ff372f31e4 100644 (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);
 }
 
index 17c02ccebd93b8424a3bf6b8d8c9a2a89dde210a..6c44daf90a30f06f645b6dc6c51758fbee780871 100644 (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;
     }
   }
index f3bcc59fd470ef3cf4bf6417ef25f98f8225ba22..f531e6a93932239a0951f271c97fb5e9b401c1d3 100644 (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 )
index fce0ac8ed0b455a8f9b9f3899de987e9bba5616f..efab84190811b6495f9086c8a68f9a9916ff6bf3 100644 (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
index 2bc20210bb4de9f42e27d5df28e366f0949a2c9a..29105d109c25a042bc2a03172ca5f93a5d951ea9 100644 (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;
 }
 
index a6e9b7304dcde0de133641fac6c3a78d490b260e..d7ea86bc50c0dcd619a501bcdebf46adb61fea3f 100644 (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);
+}
index 9be6d174c0e98b981e9e1c31f98a8deeb3a0c727..13f52ba755119428d6d2821673058bcfa47e97ca 100644 (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__ */
index 04508c7a7c6b1f33933670a5451765b4b9422fa4..4fe4aea81d2d851552e3faa225c6733940651762 100644 (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);
+}
index 7c17807615edda7a952e6dacc8715eb6cff05d1a..ecd22413cabf2804e75baf91bda2fbe4f868f64c 100644 (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__ */
index 322a25179c4fd4b26e4e406b47114ac45eb324a9..4216fee253d5d70e65e4e5647ef9aea67656e928 100644 (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;
 }
index 13a97cd200e8d2819b7adc075087d7b563742f0f..592e7b616584063ba5a41c97a09282235b0427e9 100644 (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);
+}
 
 /**
  *
index 7afc3ca1c7cc65ec4045cb35add3765b3d887a57..6fa15037f0502e01bd96b1c6bfeb297dac1558b0 100644 (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);
index b35fc7677025c06b08796fad8aa921bb055b5889..5b0d7c50b615bccb0ed3df78fa02510e7cacb62c 100644 (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;
 }
index 702bdd7a1d4b4c9ae75482e97749533a62443698..a6c5fb54e4b87b5469330b3f5c563aaab61a3beb 100644 (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  
index 232c6868eec2abc34cf33bc47f515615b10e78be..dfce07043862e6d65af93b6a144d2d99f74effff 100644 (file)
@@ -77,6 +77,15 @@ hts_settings_init(const char *confpath)
   }
 }
 
+/**
+ *
+ */
+void
+hts_settings_done(void)
+{
+  free(settingspath);
+}
+
 /**
  *
  */
index 8d29d54b06dd3fdf29315a037faea96421f38cd9..515828243adbc77e6c74a379f7807b30d11f23dd 100644 (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, ...);
index bde6f6cba114fcdfcf790d9875d79306c246b966..ebb6e2f369f5edd517734db499168acdab3cfd93 100644 (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
  * *************************************************************************/
index eca8c8d607295c32d3c192eeca07e7ccade4f57d..86ff2c6ce27637eac6b6652109f198da9d511a78 100644 (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);
index 8d78809a1d85fab94ea472d43eca61f59796a21e..136a842e9837c71f01aa1b609b9c9b4c14eb089a 100644 (file)
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -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;
+  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);
 }
index b09544627c3684823a1200c465256bc23aea4863..7006e4d235544e4dacb3a4ce905cb15ffeb71e9d 100644 (file)
--- a/src/tcp.h
+++ b/src/tcp.h
@@ -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);
index 0bb2be80004da10c38aa48e9fa134713f70d93e2..b8c68f866143bbefd68110d5eb2973dc8c0e810a 100644 (file)
@@ -69,6 +69,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;
@@ -539,6 +541,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,
@@ -603,6 +607,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)
+
 #ifdef PLATFORM_LINUX
 /* glibc wrapper */
 #if !__GLIBC_PREREQ(2,8)
index ece17b33e0ebbee6c2ad3ef17076ef775f1e4a68..772fbd86c16e9dfe380412bfbe5845efbc237099 100644 (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);
 }
index f5f5c454a9affd646d3ea1d8422d7e68e6bc8fb9..06bb47326be199f6d3b4d60ad8222ba1d85005f4 100644 (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__)
index aee51b7831e735aca1406bf9809df41fa9b26074..574a9fa2edcdf54f64dcc1aef34774e4d2eab422 100644 (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);
index 8e30977436b0932d0f3a5db5424afd72a49ed7c2..443769dbfebf674471b3fba926b4e60b31fadaef 100755 (executable)
@@ -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);
   }
 }
 
index 9d8a523c7264e0b62d37a12a43f8fe76c7784c53..01aedaba75167972df26ab2798d759c0f5b110ea 100644 (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");
index cf10d8b56863db858e1efa22454140b3f29b5830..ca5f5f5219cfee82603af148e4b6dec02915b396 100644 (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();
+}
index 409f745ed1d0158850812a1b3003f92f7fa8cccf..2a2e3e5cc4ef1c0151eb9bb8c4d720703a9ab716 100644 (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);
index 4343fc505bf4fe03006c101412293bdfd19d7335..c8ec1967964e678d1992355fffae71e7d5fe2f4e 100644 (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);