]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
memoryinfo: initial work
authorJaroslav Kysela <perex@perex.cz>
Sat, 12 Mar 2016 16:43:22 +0000 (17:43 +0100)
committerJaroslav Kysela <perex@perex.cz>
Sat, 12 Mar 2016 21:39:35 +0000 (22:39 +0100)
30 files changed:
Makefile
src/api/api_config.c
src/atomic.h
src/channels.c
src/clock.h
src/epgdb.c
src/idnode.c
src/idnode.h
src/input/mpegts/mpegts_service.c
src/lang_str.c
src/lang_str.h
src/main.c
src/memoryinfo.c [new file with mode: 0644]
src/memoryinfo.h [new file with mode: 0644]
src/muxer/muxer_pass.c
src/packet.c
src/packet.h
src/parsers/parser_avc.c
src/parsers/parser_hevc.c
src/prop.c
src/prop.h
src/service.c
src/service.h
src/streaming.c
src/subscriptions.c
src/timeshift/timeshift_reader.c
src/timeshift/timeshift_writer.c
src/tvheadend.h
src/webui/static/app/tvheadend.js
src/webui/static/app/tvhlog.js

index ec95b5ea1ac315d7d9526067f49ac45039003601..1e12a60846d4d06cb73a491f044bf19260a77aae 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -213,7 +213,8 @@ SRCS-1 = \
        src/profile.c \
        src/bouquet.c \
        src/lock.c \
-       src/wizard.c
+       src/wizard.c \
+       src/memoryinfo.c
 SRCS = $(SRCS-1)
 I18N-C = $(SRCS-1)
 
index 6a85622cdec488d8daf6f09842385f0b1ebd96ff..45a38843b5d71d96d726c3d961b34a9013101668 100644 (file)
@@ -20,6 +20,7 @@
 #include "tvheadend.h"
 #include "channels.h"
 #include "access.h"
+#include "memoryinfo.h"
 #include "api.h"
 #include "config.h"
 
@@ -31,6 +32,19 @@ api_config_capabilities(access_t *perm, void *opaque, const char *op,
     return 0;
 }
 
+static void
+api_memoryinfo_grid
+  ( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf, htsmsg_t *args )
+{
+  memoryinfo_t *my;
+
+  LIST_FOREACH(my, &memoryinfo_entries, my_link) {
+    if (my->my_update)
+      my->my_update(my);
+    idnode_set_add(ins, (idnode_t*)my, &conf->filter, perm->aa_lang_ui);
+  }
+}
+
 void
 api_config_init ( void )
 {
@@ -40,6 +54,8 @@ api_config_init ( void )
     { "config/save",         ACCESS_ADMIN, api_idnode_save_simple, &config },
     { "tvhlog/config/load",  ACCESS_ADMIN, api_idnode_load_simple, &tvhlog_conf },
     { "tvhlog/config/save",  ACCESS_ADMIN, api_idnode_save_simple, &tvhlog_conf },
+    { "memoryinfo/class",    ACCESS_ADMIN, api_idnode_class, (void *)&memoryinfo_class },
+    { "memoryinfo/grid",     ACCESS_ADMIN, api_idnode_grid, api_memoryinfo_grid },
     { NULL },
   };
 
index aba9476180b56c7a8ae21afd97f76bc9eb05f109..42b839ce3da3a7a57241423b2a903603fc4ab44f 100644 (file)
@@ -82,6 +82,21 @@ atomic_add_time_t(volatile time_t *ptr, time_t incr)
  * Atomic ADD and FETCH operation
  */
 
+static inline int64_t
+atomic_pre_add_s64(volatile int64_t *ptr, int64_t incr)
+{
+#if ENABLE_ATOMIC64
+  return __sync_add_and_fetch(ptr, incr);
+#else
+  int64_t ret;
+  pthread_mutex_lock(&atomic_lock);
+  *ptr += incr;
+  ret = *ptr;
+  pthread_mutex_unlock(&atomic_lock);
+  return ret;
+#endif
+}
+
 static inline uint64_t
 atomic_pre_add_u64(volatile uint64_t *ptr, uint64_t incr)
 {
@@ -97,6 +112,31 @@ atomic_pre_add_u64(volatile uint64_t *ptr, uint64_t incr)
 #endif
 }
 
+/*
+ * Atomic ADD and FETCH operation with PEAK (MAX)
+ */
+
+static inline int64_t
+atomic_pre_add_s64_peak(volatile int64_t *ptr, int64_t incr,
+                        volatile int64_t *peak)
+{
+#if ENABLE_ATOMIC64
+  int64_t ret = __sync_add_and_fetch(ptr, incr);
+  if (__sync_fetch_and_add(peak, 0) < ret)
+    __sync_lock_test_and_set(peak, ret);
+  return ret;
+#else
+  int64_t ret;
+  pthread_mutex_lock(&atomic_lock);
+  *ptr += incr;
+  ret = *ptr;
+  if (*peak < ret)
+    *peak = ret;
+  pthread_mutex_unlock(&atomic_lock);
+  return ret;
+#endif
+}
+
 /*
  * Atomic DEC operation
  */
@@ -247,3 +287,25 @@ atomic_set_time_t(volatile time_t *ptr, time_t val)
 {
   return atomic_exchange_time_t(ptr, val);
 }
+
+/*
+ * Atomic set operation + peak (MAX)
+ */
+
+static inline int64_t
+atomic_set_s64_peak(volatile int64_t *ptr, int64_t val, volatile int64_t *peak)
+{
+#if ENABLE_ATOMIC64
+  int64_t ret = atomic_exchange_s64(ptr, val);
+  if (val > atomic_get_s64(peak))
+    atomic_set_s64(peak, val);
+  return ret;
+#else
+  pthread_mutex_lock(&atomic_lock);
+  *ptr = val;
+  if (val > *peak)
+    *peak = val;
+  pthread_mutex_unlock(&atomic_lock);
+  return ret;
+#endif
+}
index 6365c353cb0f3fb81ec077580d05f0582b25e761..a29bcc2034477a67b87fcd57fa6a79cb94507479 100644 (file)
@@ -44,6 +44,7 @@
 #include "htsbuf.h"
 #include "bouquet.h"
 #include "intlconv.h"
+#include "memoryinfo.h"
 
 #define CHANNEL_BLANK_NAME  "{name-not-set}"
 
@@ -1064,7 +1065,30 @@ channel_delete ( channel_t *ch, int delconf )
   free(ch);
 }
 
+/**
+ *
+ */
 
+static void channels_memoryinfo_update(memoryinfo_t *my)
+{
+  channel_t *ch;
+  int64_t size = 0, count = 0;
+
+  lock_assert(&global_lock);
+  CHANNEL_FOREACH(ch) {
+    size += sizeof(*ch);
+    size += tvh_strlen(ch->ch_epg_parent);
+    size += tvh_strlen(ch->ch_name);
+    size += tvh_strlen(ch->ch_icon);
+    count++;
+  }
+  memoryinfo_update(my, size, count);
+}
+
+static memoryinfo_t channels_memoryinfo = {
+  .my_name = "Channels",
+  .my_update = channels_memoryinfo_update
+};
 
 /**
  *
@@ -1078,6 +1102,7 @@ channel_init ( void )
   char *s;
 
   RB_INIT(&channels);
+  memoryinfo_register(&channels_memoryinfo);
 
   /* Tags */
   channel_tag_init();
@@ -1116,6 +1141,7 @@ channel_done ( void )
   pthread_mutex_lock(&global_lock);
   while ((ch = RB_FIRST(&channels)) != NULL)
     channel_delete(ch, 0);
+  memoryinfo_unregister(&channels_memoryinfo);
   pthread_mutex_unlock(&global_lock);
   channel_tag_done();
 }
@@ -1485,6 +1511,31 @@ channel_tag_find_by_identifier(uint32_t id) {
   return NULL;
 }
 
+/**
+ *
+ */
+
+static void channel_tags_memoryinfo_update(memoryinfo_t *my)
+{
+  channel_tag_t *ct;
+  int64_t size = 0, count = 0;
+
+  lock_assert(&global_lock);
+  TAILQ_FOREACH(ct, &channel_tags, ct_link) {
+    size += sizeof(*ct);
+    size += tvh_strlen(ct->ct_name);
+    size += tvh_strlen(ct->ct_comment);
+    size += tvh_strlen(ct->ct_icon);
+    count++;
+  }
+  memoryinfo_update(my, size, count);
+}
+
+static memoryinfo_t channel_tags_memoryinfo = {
+  .my_name = "Channel tags",
+  .my_update = channel_tags_memoryinfo_update
+};
+
 /**
  *  Init / Done
  */
@@ -1495,6 +1546,7 @@ channel_tag_init ( void )
   htsmsg_t *c, *m;
   htsmsg_field_t *f;
 
+  memoryinfo_register(&channel_tags_memoryinfo);
   TAILQ_INIT(&channel_tags);
   if ((c = hts_settings_load("channel/tag")) != NULL) {
     HTSMSG_FOREACH(f, c) {
index 7d914e469a64059ce61b79088cdf1c75a6de0c0f..3035bae4d57ca4a033ca4aef764461856e5569ce 100644 (file)
@@ -1,6 +1,6 @@
 /*
- *  Tvheadend - structures
- *  Copyright (C) 2007 Andreas Ă–man
+ *  Tvheadend - clock support
+ *  Copyright (C) 2016 Jaroslav Kysela
  *
  *  This program is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
index 111960f24f6f730700321fc8190647f2b5dbc2d0..aebcbc462d00bef07a7f1ef9e04eb4aba196ee5e 100644 (file)
@@ -32,6 +32,7 @@
 #include "epg.h"
 #include "epggrab.h"
 #include "config.h"
+#include "memoryinfo.h"
 
 #define EPG_DB_VERSION 2
 #define EPG_DB_ALLOC_STEP (1024*1024)
@@ -146,6 +147,125 @@ _epgdb_v2_process( char **sect, htsmsg_t *m, epggrab_stats_t *stats )
   }
 }
 
+/*
+ * Memoryinfo
+ */
+
+static void epg_memoryinfo_brands_update(memoryinfo_t *my)
+{
+  epg_object_t *eo;
+  epg_brand_t *eb;
+  int64_t size = 0, count = 0;
+
+  RB_FOREACH(eo, &epg_brands, uri_link) {
+    eb = (epg_brand_t *)eo;
+    size += sizeof(*eb);
+    size += tvh_strlen(eb->uri);
+    size += lang_str_size(eb->title);
+    size += lang_str_size(eb->summary);
+    size += tvh_strlen(eb->image);
+    count++;
+  }
+  memoryinfo_update(my, size, count);
+}
+
+static memoryinfo_t epg_memoryinfo_brands = {
+  .my_name = "EPG Brands",
+  .my_update = epg_memoryinfo_brands_update
+};
+
+static void epg_memoryinfo_seasons_update(memoryinfo_t *my)
+{
+  epg_object_t *eo;
+  epg_season_t *es;
+  int64_t size = 0, count = 0;
+
+  RB_FOREACH(eo, &epg_seasons, uri_link) {
+    es = (epg_season_t *)eo;
+    size += sizeof(*es);
+    size += tvh_strlen(es->uri);
+    size += lang_str_size(es->summary);
+    size += tvh_strlen(es->image);
+    count++;
+  }
+  memoryinfo_update(my, size, count);
+}
+
+static memoryinfo_t epg_memoryinfo_seasons = {
+  .my_name = "EPG Seasons",
+  .my_update = epg_memoryinfo_seasons_update
+};
+
+static void epg_memoryinfo_episodes_update(memoryinfo_t *my)
+{
+  epg_object_t *eo;
+  epg_episode_t *ee;
+  int64_t size = 0, count = 0;
+
+  RB_FOREACH(eo, &epg_episodes, uri_link) {
+    ee = (epg_episode_t *)eo;
+    size += sizeof(*ee);
+    size += tvh_strlen(ee->uri);
+    size += lang_str_size(ee->title);
+    size += lang_str_size(ee->subtitle);
+    size += lang_str_size(ee->summary);
+    size += lang_str_size(ee->description);
+    size += tvh_strlen(ee->image);
+    size += tvh_strlen(ee->epnum.text);
+    count++;
+  }
+  memoryinfo_update(my, size, count);
+}
+
+static memoryinfo_t epg_memoryinfo_episodes = {
+  .my_name = "EPG Episodes",
+  .my_update = epg_memoryinfo_episodes_update
+};
+
+static void epg_memoryinfo_serieslinks_update(memoryinfo_t *my)
+{
+  epg_object_t *eo;
+  epg_serieslink_t *es;
+  int64_t size = 0, count = 0;
+
+  RB_FOREACH(eo, &epg_serieslinks, uri_link) {
+    es = (epg_serieslink_t *)eo;
+    size += sizeof(*es);
+    size += tvh_strlen(es->uri);
+    count++;
+  }
+  memoryinfo_update(my, size, count);
+}
+
+static memoryinfo_t epg_memoryinfo_serieslinks = {
+  .my_name = "EPG Series Links",
+  .my_update = epg_memoryinfo_serieslinks_update
+};
+
+static void epg_memoryinfo_broadcasts_update(memoryinfo_t *my)
+{
+  channel_t *ch;
+  epg_broadcast_t *ebc;
+  int64_t size = 0, count = 0;
+
+  CHANNEL_FOREACH(ch) {
+    if (ch->ch_epg_parent) continue;
+    RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) {
+      size += sizeof(*ebc);
+      size += tvh_strlen(ebc->uri);
+      size += lang_str_size(ebc->summary);
+      size += lang_str_size(ebc->description);
+      count++;
+    }
+  }
+  memoryinfo_update(my, size, count);
+}
+
+static memoryinfo_t epg_memoryinfo_broadcasts = {
+  .my_name = "EPG Broadcasts",
+  .my_update = epg_memoryinfo_broadcasts_update
+};
+
 /*
  * Recovery
  */
@@ -170,6 +290,12 @@ void epg_init ( void )
   struct sigaction act, oldact;
   char *sect = NULL;
 
+  memoryinfo_register(&epg_memoryinfo_brands);
+  memoryinfo_register(&epg_memoryinfo_seasons);
+  memoryinfo_register(&epg_memoryinfo_episodes);
+  memoryinfo_register(&epg_memoryinfo_serieslinks);
+  memoryinfo_register(&epg_memoryinfo_broadcasts);
+
   /* Find the right file (and version) */
   while (fd < 0 && ver > 0) {
     fd = hts_settings_open_file(0, "epgdb.v%d", ver);
@@ -298,6 +424,11 @@ void epg_done ( void )
   CHANNEL_FOREACH(ch)
     epg_channel_unlink(ch);
   epg_skel_done();
+  memoryinfo_unregister(&epg_memoryinfo_brands);
+  memoryinfo_unregister(&epg_memoryinfo_seasons);
+  memoryinfo_unregister(&epg_memoryinfo_episodes);
+  memoryinfo_unregister(&epg_memoryinfo_serieslinks);
+  memoryinfo_unregister(&epg_memoryinfo_broadcasts);
   pthread_mutex_unlock(&global_lock);
 }
 
index 90b9a01a8e7be227519b3733805a1ab2acbeeadc..c7b4fa2b1da6942b8ad72234a4c3daa157280195 100644 (file)
@@ -434,6 +434,33 @@ idnode_get_s64
   return 1;
 }
 
+/*
+ * Get field as signed 64-bit int
+ */
+int
+idnode_get_s64_atomic
+  ( idnode_t *self, const char *key, int64_t *s64 )
+{
+  const property_t *p = idnode_find_prop(self, key);
+  if (p) {
+    const void *ptr;
+    if (p->islist)
+      return 1;
+    else if (p->get)
+      ptr = p->get(self);
+    else
+      ptr = ((void*)self) + p->off;
+    switch (p->type) {
+      case PT_S64_ATOMIC:
+        *s64 = atomic_get_s64((int64_t*)ptr);
+        return 0;
+      default:
+        break;
+    }
+  }
+  return 1;
+}
+
 /*
  * Get field as double
  */
@@ -733,6 +760,17 @@ idnode_cmp_sort
           return safecmp(s64b, s64a);
       }
       break;
+    case PT_S64_ATOMIC:
+      {
+        int64_t s64a = 0, s64b = 0;
+        idnode_get_s64_atomic(ina, sort->key, &s64a);
+        idnode_get_s64_atomic(inb, sort->key, &s64b);
+        if (sort->dir == IS_ASC)
+          return safecmp(s64a, s64b);
+        else
+          return safecmp(s64b, s64a);
+      }
+      break;
     case PT_DBL:
       {
         double dbla = 0, dblb = 0;
index 380cfc85083e918db56a52d60b1711b94f7654fd..f859fbb92c56cb2cba4af60621de0707fc14b3c3 100644 (file)
@@ -269,6 +269,7 @@ int idnode_list_set2 ( idnode_t *in2, idnode_list_head_t *in2_list,
 const char *idnode_get_str (idnode_t *self, const char *key );
 int         idnode_get_u32 (idnode_t *self, const char *key, uint32_t *u32);
 int         idnode_get_s64 (idnode_t *self, const char *key,  int64_t *s64);
+int         idnode_get_s64_atomic (idnode_t *self, const char *key, int64_t *s64);
 int         idnode_get_dbl (idnode_t *self, const char *key,   double *dbl);
 int         idnode_get_bool(idnode_t *self, const char *key, int *b);
 int         idnode_get_time(idnode_t *self, const char *key, time_t *tm);
index 4bdc095928f0c58d6f56d916b18576a680094537..db7fd4aa958bd464fee6a61c7f6973d732fa1f86 100644 (file)
@@ -696,6 +696,18 @@ mpegts_service_satip_source ( service_t *t )
   return mn ? mn->mn_satip_source : -1;
 }
 
+static void
+mpegts_service_memoryinfo ( service_t *t, int64_t *size )
+{
+  mpegts_service_t *ms = (mpegts_service_t*)t;
+  *size += sizeof(*ms);
+  *size += tvh_strlen(ms->s_nicename);
+  *size += tvh_strlen(ms->s_dvb_svcname);
+  *size += tvh_strlen(ms->s_dvb_provider);
+  *size += tvh_strlen(ms->s_dvb_cridauth);
+  *size += tvh_strlen(ms->s_dvb_charset);
+}
+
 /* **************************************************************************
  * Creation/Location
  * *************************************************************************/
@@ -749,6 +761,7 @@ mpegts_service_create0
   s->s_channel_icon   = mpegts_service_channel_icon;
   s->s_mapped         = mpegts_service_mapped;
   s->s_satip_source   = mpegts_service_satip_source;
+  s->s_memoryinfo     = mpegts_service_memoryinfo;
 
   pthread_mutex_lock(&s->s_stream_mutex);
   service_make_nicename((service_t*)s);
@@ -1019,6 +1032,7 @@ mpegts_service_create_raw ( mpegts_mux_t *mm )
   s->s_link           = mpegts_service_link;
   s->s_unlink         = mpegts_service_unlink;
   s->s_satip_source   = mpegts_service_satip_source;
+  s->s_memoryinfo     = mpegts_service_memoryinfo;
 
   pthread_mutex_lock(&s->s_stream_mutex);
   free(s->s_nicename);
index eb040de50f527f81db31cf8cc65a7e27755bc904..fd9cf0b0cce5f0e504fe3a706236decc80ef45ac 100644 (file)
@@ -311,6 +311,20 @@ int lang_str_empty(lang_str_t* str) {
   return strempty(lang_str_get(str, NULL));
 }
 
+size_t lang_str_size(const lang_str_t *ls)
+{
+  lang_str_ele_t *e;
+  size_t size;
+  if (!ls) return 0;
+  size = sizeof(*ls);
+  RB_FOREACH(e, ls, link) {
+    size += sizeof(*e);
+    size += tvh_strlen(e->str);
+    size += tvh_strlen(e->lang);
+  }
+  return size;
+}
+
 void lang_str_done( void )
 {
   SKEL_FREE(lang_str_ele_skel);
index d8e3b5f6c96d5a44d0909fd1d9235ef6d5613224..d31dbddfdada86e3972d445e86dac79d5d76f76c 100644 (file)
@@ -68,6 +68,9 @@ int             lang_str_compare ( const lang_str_t *ls1, const lang_str_t *ls2
 int             strempty(const char* c);
 int             lang_str_empty(lang_str_t* str);
 
+/* Size in bytes */
+size_t          lang_str_size ( const lang_str_t *ls );
+
 /* Init/Done */
 void            lang_str_done( void );
 
index 3ab20345ea60d9fb8cb3301370320f6ffb286f1c..7c191a96929184325a9e909345b65777c1fa8359 100644 (file)
@@ -71,6 +71,8 @@
 #include "profile.h"
 #include "bouquet.h"
 #include "tvhtime.h"
+#include "packet.h"
+#include "memoryinfo.h"
 
 #ifdef PLATFORM_LINUX
 #include <sys/prctl.h>
@@ -186,6 +188,7 @@ static pthread_cond_t gtimer_cond;
 static TAILQ_HEAD(, tasklet) tasklets;
 static tvh_cond_t tasklet_cond;
 static pthread_t tasklet_tid;
+static memoryinfo_t tasklet_memoryinfo = { .my_name = "Tasklet" };
 
 static void
 handle_sigpipe(int x)
@@ -364,6 +367,7 @@ tasklet_arm_alloc(tsk_callback_t *callback, void *opaque)
 {
   tasklet_t *tsk = calloc(1, sizeof(*tsk));
   if (tsk) {
+    memoryinfo_alloc(&tasklet_memoryinfo, sizeof(*tsk));
     tsk->tsk_allocated = 1;
     tasklet_arm(tsk, callback, opaque);
   }
@@ -422,8 +426,10 @@ tasklet_flush()
     TAILQ_REMOVE(&tasklets, tsk, tsk_link);
     tsk->tsk_callback(tsk->tsk_opaque, 1);
     tsk->tsk_callback = NULL;
-    if (tsk->tsk_allocated)
+    if (tsk->tsk_allocated) {
+      memoryinfo_free(&tasklet_memoryinfo, sizeof(*tsk));
       free(tsk);
+    }
   }
 
   pthread_mutex_unlock(&tasklet_lock);
@@ -453,8 +459,10 @@ tasklet_thread ( void *aux )
     tsk_cb = tsk->tsk_callback;
     opaque = tsk->tsk_opaque;
     tsk->tsk_callback = NULL;
-    if (tsk->tsk_allocated)
+    if (tsk->tsk_allocated) {
+      memoryinfo_free(&tasklet_memoryinfo, sizeof(*tsk));
       free(tsk);
+    }
     /* now, the callback can be safely called */
     if (tsk_cb) {
       pthread_mutex_unlock(&tasklet_lock);
@@ -1125,6 +1133,12 @@ main(int argc, char **argv)
   spawn_init();
   config_init(opt_nobackup == 0);
 
+  /* Memoryinfo */
+  memoryinfo_register(&tasklet_memoryinfo);
+  memoryinfo_register(&pkt_memoryinfo);
+  memoryinfo_register(&pktbuf_memoryinfo);
+  memoryinfo_register(&pktref_memoryinfo);
+
   /**
    * Initialize subsystems
    */
diff --git a/src/memoryinfo.c b/src/memoryinfo.c
new file mode 100644 (file)
index 0000000..d76a914
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *  Tvheadend - memory info support
+ *  Copyright (C) 2016 Jaroslav Kysela
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tvheadend.h"
+#include "idnode.h"
+#include "access.h"
+#include "memoryinfo.h"
+
+struct memoryinfo_list memoryinfo_entries;
+
+static const char *
+service_class_get_title ( idnode_t *self, const char *lang )
+{
+  return ((memoryinfo_t *)self)->my_name;
+}
+
+const idclass_t memoryinfo_class = {
+  .ic_class      = "memoryinfo",
+  .ic_caption    = N_("Memory information"),
+  .ic_event      = "memoryinfo",
+  .ic_perm_def   = ACCESS_ADMIN,
+  .ic_get_title  = service_class_get_title,
+  .ic_properties = (const property_t[]){
+    {
+      .type     = PT_STR,
+      .id       = "name",
+      .name     = N_("Name"),
+      .off      = offsetof(memoryinfo_t, my_name),
+      .opts     = PO_RDONLY | PO_NOSAVE,
+    },
+    {
+      .type     = PT_S64_ATOMIC,
+      .id       = "size",
+      .name     = N_("Size"),
+      .off      = offsetof(memoryinfo_t, my_size),
+      .opts     = PO_RDONLY | PO_NOSAVE,
+    },
+    {
+      .type     = PT_S64_ATOMIC,
+      .id       = "peak_size",
+      .name     = N_("Peak size"),
+      .off      = offsetof(memoryinfo_t, my_peak_size),
+      .opts     = PO_RDONLY | PO_NOSAVE,
+    },
+    {
+      .type     = PT_S64_ATOMIC,
+      .id       = "count",
+      .name     = N_("Counf of objects"),
+      .off      = offsetof(memoryinfo_t, my_count),
+      .opts     = PO_RDONLY | PO_NOSAVE,
+    },
+    {
+      .type     = PT_S64_ATOMIC,
+      .id       = "peak_count",
+      .name     = N_("Peak counf of objects"),
+      .off      = offsetof(memoryinfo_t, my_peak_count),
+      .opts     = PO_RDONLY | PO_NOSAVE,
+    },
+    {}
+  }
+};
diff --git a/src/memoryinfo.h b/src/memoryinfo.h
new file mode 100644 (file)
index 0000000..44d127f
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  Tvheadend - memory info support
+ *  Copyright (C) 2016 Jaroslav Kysela
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TVHEADEND_MEMORYINFO_H
+#define TVHEADEND_MEMORYINFO_H
+
+#include "idnode.h"
+
+struct memoryinfo;
+
+typedef void (*memoryinfo_cb_t)(struct memoryinfo *my);
+
+typedef struct memoryinfo {
+  idnode_t               my_idnode;
+  LIST_ENTRY(memoryinfo) my_link;
+  const char            *my_name;
+  void                  *my_opaque;
+  memoryinfo_cb_t        my_update;
+  int64_t                my_size;
+  int64_t                my_peak_size;
+  int64_t                my_count;
+  int64_t                my_peak_count;
+} memoryinfo_t;
+
+extern struct memoryinfo_list memoryinfo_entries;
+extern const idclass_t memoryinfo_class;
+
+static inline void memoryinfo_register(memoryinfo_t *my)
+{
+  LIST_INSERT_HEAD(&memoryinfo_entries, my, my_link);
+  idnode_insert(&my->my_idnode, NULL, &memoryinfo_class, 0);
+}
+
+static inline void memoryinfo_unregister(memoryinfo_t *my)
+{
+  LIST_REMOVE(my, my_link);
+  idnode_unlink(&my->my_idnode);
+}
+
+static inline void memoryinfo_update(memoryinfo_t *my, int64_t size, int64_t count)
+{
+  atomic_set_s64_peak(&my->my_size, size, &my->my_peak_size);
+  atomic_set_s64_peak(&my->my_count, count, &my->my_peak_count);
+}
+
+static inline void memoryinfo_alloc(memoryinfo_t *my, int64_t size)
+{
+  atomic_pre_add_s64_peak(&my->my_size, size, &my->my_peak_size);
+  atomic_pre_add_s64_peak(&my->my_count, 1, &my->my_peak_count);
+}
+
+static inline void memoryinfo_append(memoryinfo_t *my, int64_t size)
+{
+  atomic_pre_add_s64_peak(&my->my_size, size, &my->my_peak_size);
+}
+
+static inline void memoryinfo_free(memoryinfo_t *my, int64_t size)
+{
+  atomic_dec_s64(&my->my_size, size);
+  atomic_dec_s64(&my->my_count, 1);
+}
+
+
+#endif /* TVHEADEND_MEMORYINFO_H */
index 87a97cf7be9543a7ee207f2e23349f55e663558a..c569bd81e6621d0d482827b4ce41ae367df5179c 100644 (file)
@@ -436,14 +436,14 @@ pass_muxer_write_ts(muxer_t *m, pktbuf_t *pb)
 {
   pass_muxer_t *pm = (pass_muxer_t*)m;
   int l, pid;
-  uint8_t *tsb, *pkt = pb->pb_data;
-  size_t  len = pb->pb_size, len2;
+  uint8_t *tsb, *pkt = pktbuf_ptr(pb);
+  size_t  len = pktbuf_len(pb), len2;
   
   /* Rewrite PAT/PMT in operation */
   if (pm->m_config.m_rewrite_pat || pm->m_config.m_rewrite_pmt ||
       pm->pm_rewrite_sdt || pm->pm_rewrite_eit) {
 
-    for (tsb = pb->pb_data, len2 = pb->pb_size, len = 0;
+    for (tsb = pktbuf_ptr(pb), len2 = pktbuf_len(pb), len = 0;
          len2 > 0; tsb += l, len2 -= l) {
 
       pid = (tsb[1] & 0x1f) << 8 | tsb[2];
index 91755066355469e4c52b94d363c081d7482b0820..a73663ec99b22eea5c1786fb69c88a2601e9fade 100644 (file)
 #include "packet.h"
 #include "string.h"
 #include "atomic.h"
+#include "memoryinfo.h"
 
 #ifndef PKTBUF_DATA_ALIGN
 #define PKTBUF_DATA_ALIGN 64
 #endif
 
+memoryinfo_t pkt_memoryinfo = { .my_name = "Packets" };
+memoryinfo_t pktbuf_memoryinfo = { .my_name = "Packet buffers" };
+memoryinfo_t pktref_memoryinfo = { .my_name = "Packet references" };
+
 /*
  *
  */
 static void
 pkt_destroy(th_pkt_t *pkt)
 {
-  pktbuf_ref_dec(pkt->pkt_payload);
-  pktbuf_ref_dec(pkt->pkt_meta);
+  if (pkt) {
+    pktbuf_ref_dec(pkt->pkt_payload);
+    pktbuf_ref_dec(pkt->pkt_meta);
 
-  free(pkt);
+    free(pkt);
+    memoryinfo_free(&pkt_memoryinfo, sizeof(*pkt));
+  }
 }
 
 
@@ -49,14 +57,63 @@ pkt_alloc(const void *data, size_t datalen, int64_t pts, int64_t dts)
   th_pkt_t *pkt;
 
   pkt = calloc(1, sizeof(th_pkt_t));
-  if(datalen)
-    pkt->pkt_payload = pktbuf_alloc(data, datalen);
-  pkt->pkt_dts = dts;
-  pkt->pkt_pts = pts;
-  pkt->pkt_refcount = 1;
+  if (pkt) {
+    if(datalen)
+      pkt->pkt_payload = pktbuf_alloc(data, datalen);
+    pkt->pkt_dts = dts;
+    pkt->pkt_pts = pts;
+    pkt->pkt_refcount = 1;
+    memoryinfo_alloc(&pkt_memoryinfo, sizeof(*pkt));
+  }
   return pkt;
 }
 
+
+/**
+ *
+ */
+th_pkt_t *
+pkt_copy_shallow(th_pkt_t *pkt)
+{
+  th_pkt_t *n = malloc(sizeof(th_pkt_t));
+
+  if (n) {
+    *n = *pkt;
+
+    n->pkt_refcount = 1;
+
+    pktbuf_ref_inc(n->pkt_meta);
+    pktbuf_ref_inc(n->pkt_payload);
+
+    memoryinfo_alloc(&pkt_memoryinfo, sizeof(*pkt));
+  }
+
+  return n;
+}
+
+
+/**
+ *
+ */
+th_pkt_t *
+pkt_copy_nodata(th_pkt_t *pkt)
+{
+  th_pkt_t *n = malloc(sizeof(th_pkt_t));
+
+  if (n) {
+    *n = *pkt;
+
+    n->pkt_refcount = 1;
+
+    n->pkt_meta = n->pkt_payload = NULL;
+
+    memoryinfo_alloc(&pkt_memoryinfo, sizeof(*pkt));
+  }
+
+  return n;
+}
+
+
 /**
  *
  */
@@ -95,10 +152,13 @@ pktref_clear_queue(struct th_pktref_queue *q)
 {
   th_pktref_t *pr;
 
-  while((pr = TAILQ_FIRST(q)) != NULL) {
-    TAILQ_REMOVE(q, pr, pr_link);
-    pkt_ref_dec(pr->pr_pkt);
-    free(pr);
+  if (q) {
+    while((pr = TAILQ_FIRST(q)) != NULL) {
+      TAILQ_REMOVE(q, pr, pr_link);
+      pkt_ref_dec(pr->pr_pkt);
+      free(pr);
+      memoryinfo_free(&pktref_memoryinfo, sizeof(*pr));
+    }
   }
 }
 
@@ -110,8 +170,11 @@ void
 pktref_enqueue(struct th_pktref_queue *q, th_pkt_t *pkt)
 {
   th_pktref_t *pr = malloc(sizeof(th_pktref_t));
-  pr->pr_pkt = pkt;
-  TAILQ_INSERT_TAIL(q, pr, pr_link);
+  if (pr) {
+    pr->pr_pkt = pkt;
+    TAILQ_INSERT_TAIL(q, pr, pr_link);
+    memoryinfo_alloc(&pktref_memoryinfo, sizeof(*pr));
+  }
 }
 
 
@@ -121,27 +184,13 @@ pktref_enqueue(struct th_pktref_queue *q, th_pkt_t *pkt)
 void
 pktref_remove(struct th_pktref_queue *q, th_pktref_t *pr)
 {
-  TAILQ_REMOVE(q, pr, pr_link);
-  pkt_ref_dec(pr->pr_pkt);
-  free(pr);
-}
-
-
-/**
- *
- */
-th_pkt_t *
-pkt_copy_shallow(th_pkt_t *pkt)
-{
-  th_pkt_t *n = malloc(sizeof(th_pkt_t));
-  *n = *pkt;
-
-  n->pkt_refcount = 1;
-
-  pktbuf_ref_inc(n->pkt_meta);
-  pktbuf_ref_inc(n->pkt_payload);
-
-  return n;
+  if (pr) {
+    if (q)
+      TAILQ_REMOVE(q, pr, pr_link);
+    pkt_ref_dec(pr->pr_pkt);
+    free(pr);
+    memoryinfo_free(&pktref_memoryinfo, sizeof(*pr));
+  }
 }
 
 
@@ -152,7 +201,10 @@ th_pktref_t *
 pktref_create(th_pkt_t *pkt)
 {
   th_pktref_t *pr = malloc(sizeof(th_pktref_t));
-  pr->pr_pkt = pkt;
+  if (pr) {
+    pr->pr_pkt = pkt;
+    memoryinfo_alloc(&pktref_memoryinfo, sizeof(*pr));
+  }
   return pr;
 }
 
@@ -160,11 +212,22 @@ pktref_create(th_pkt_t *pkt)
  *
  */
 
+void
+pktbuf_destroy(pktbuf_t *pb)
+{
+  if (pb) {
+    memoryinfo_free(&pktbuf_memoryinfo, sizeof(*pb) + pb->pb_size);
+    free(pb->pb_data);
+    free(pb);
+  }
+}
+
 void
 pktbuf_ref_dec(pktbuf_t *pb)
 {
   if (pb) {
     if((atomic_add(&pb->pb_refcount, -1)) == 1) {
+      memoryinfo_free(&pktbuf_memoryinfo, sizeof(*pb) + pb->pb_size);
       free(pb->pb_data);
       free(pb);
     }
@@ -185,17 +248,23 @@ pktbuf_t *
 pktbuf_alloc(const void *data, size_t size)
 {
   pktbuf_t *pb = malloc(sizeof(pktbuf_t));
+
+  if (pb == NULL) return NULL;
   pb->pb_refcount = 1;
   pb->pb_size = size;
   pb->pb_err = 0;
-
   if(size > 0) {
     pb->pb_data = malloc(size);
-    if(data != NULL)
-      memcpy(pb->pb_data, data, size);
+    if (pb->pb_data != NULL) {
+      if (data != NULL)
+        memcpy(pb->pb_data, data, size);
+    } else {
+      pb->pb_size = 0;
+    }
   } else {
     pb->pb_data = NULL;
   }
+  memoryinfo_alloc(&pktbuf_memoryinfo, sizeof(*pb) + pb->pb_size);
   return pb;
 }
 
@@ -203,19 +272,27 @@ pktbuf_t *
 pktbuf_make(void *data, size_t size)
 {
   pktbuf_t *pb = malloc(sizeof(pktbuf_t));
-  pb->pb_refcount = 1;
-  pb->pb_size = size;
-  pb->pb_data = data;
+  if (pb) {
+    pb->pb_refcount = 1;
+    pb->pb_size = size;
+    pb->pb_data = data;
+    memoryinfo_alloc(&pktbuf_memoryinfo, sizeof(*pb) + pb->pb_size);
+  }
   return pb;
 }
 
 pktbuf_t *
 pktbuf_append(pktbuf_t *pb, const void *data, size_t size)
 {
+  void *ndata;
   if (pb == NULL)
     return pktbuf_alloc(data, size);
-  pb->pb_data = realloc(pb->pb_data, pb->pb_size + size);
-  memcpy(pb->pb_data + pb->pb_size, data, size);
-  pb->pb_size += size;
+  ndata = realloc(pb->pb_data, pb->pb_size + size);
+  if (ndata) {
+    pb->pb_data = ndata;
+    memcpy(ndata + pb->pb_size, data, size);
+    pb->pb_size += size;
+    memoryinfo_append(&pktbuf_memoryinfo, size);
+  }
   return pb;
 }
index 9825180439a0c375f91b54caa054c59f1d0b9cea..c30d434e70292fffd65cf8c9ce76262d8b0b990b 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef PACKET_H_
 #define PACKET_H_
 
+struct memoryinfo;
+
 /**
  * Packet buffer
  */
@@ -80,6 +82,13 @@ typedef struct th_pktref {
 } th_pktref_t;
 
 
+/**
+ *
+ */
+extern struct memoryinfo pkt_memoryinfo;
+extern struct memoryinfo pktbuf_memoryinfo;
+extern struct memoryinfo pktref_memoryinfo;
+
 /**
  *
  */
@@ -101,6 +110,8 @@ th_pkt_t *pkt_alloc(const void *data, size_t datalen, int64_t pts, int64_t dts);
 
 th_pkt_t *pkt_copy_shallow(th_pkt_t *pkt);
 
+th_pkt_t *pkt_copy_nodata(th_pkt_t *pkt);
+
 th_pktref_t *pktref_create(th_pkt_t *pkt);
 
 /*
@@ -109,6 +120,8 @@ th_pktref_t *pktref_create(th_pkt_t *pkt);
 
 void pktbuf_ref_dec(pktbuf_t *pb);
 
+void pktbuf_destroy(pktbuf_t *pb);
+
 pktbuf_t *pktbuf_ref_inc(pktbuf_t *pb);
 
 pktbuf_t *pktbuf_alloc(const void *data, size_t size);
index 94fc1cd8b2a364188288e71e8cf0978259d74038..10ed33c3defc6627dffef9e2b7aa2a34747fe3f4 100644 (file)
@@ -189,11 +189,7 @@ th_pkt_t *
 avc_convert_pkt(th_pkt_t *src)
 {
   sbuf_t payload;
-  th_pkt_t *pkt = malloc(sizeof(*pkt));
-
-  *pkt = *src;
-  pkt->pkt_refcount = 1;
-  pkt->pkt_meta = NULL;
+  th_pkt_t *pkt = pkt_copy_nodata(src);
 
   sbuf_init(&payload);
 
index eb1b8b703feee54f876dfc0ee7e19cc3e28738ee..cc212b0ecf86ed411720946bd07f4954b9fc5ed7 100644 (file)
@@ -1178,11 +1178,7 @@ th_pkt_t *
 hevc_convert_pkt(th_pkt_t *src)
 {
   sbuf_t payload;
-  th_pkt_t *pkt = malloc(sizeof(*pkt));
-
-  *pkt = *src;
-  pkt->pkt_refcount = 1;
-  pkt->pkt_meta = NULL;
+  th_pkt_t *pkt = pkt_copy_nodata(src);
 
   sbuf_init(&payload);
 
index 64c0be815a80ddfe09b4720c6e66b2057c537c4d..7ffb5821c6c1c083d236a3e753ad6ca2b1c91061 100644 (file)
@@ -42,6 +42,7 @@ const static struct strtab typetab[] = {
   { "u16",     PT_U16 },
   { "u32",     PT_U32 },
   { "s64",     PT_S64 },
+  { "s64",     PT_S64_ATOMIC },
   { "dbl",     PT_DBL },
   { "time",    PT_TIME },
   { "langstr", PT_LANGSTR },
@@ -165,6 +166,8 @@ prop_write_values
         PROP_UPDATE(s64, int64_t);
         break;
       }
+      case PT_S64_ATOMIC:
+        break;
       case PT_DBL: {
         if (htsmsg_field_get_dbl(f, &dbl))
           continue;
@@ -310,6 +313,9 @@ prop_read_value
       } else
         htsmsg_add_s64(m, name, *(int64_t *)val);
       break;
+    case PT_S64_ATOMIC:
+      htsmsg_add_s64(m, name, atomic_get_s64((int64_t *)val));
+      break;
     case PT_STR:
       if (optmask & PO_LOCALE) {
         if ((s = *(const char **)val))
@@ -438,6 +444,7 @@ prop_serialize_value
         htsmsg_add_u32(m, "default", pl->def.u32);
         break;
       case PT_S64:
+      case PT_S64_ATOMIC:
         htsmsg_add_s64(m, "default", pl->def.s64);
         break;
       case PT_DBL:
index a3f95f47c669da9c19e63d2f3e9768862a24ee43..404b51de47e895fdf022558f9813eef07dbd0ba9 100644 (file)
@@ -35,6 +35,7 @@ typedef enum {
   PT_U16,
   PT_U32,
   PT_S64,
+  PT_S64_ATOMIC,
   PT_DBL,
   PT_TIME,
   PT_LANGSTR,
index bc4b59ec15143f1e9918abf82e7c0ee61bba6dec..f8557a2d47f02c25971b8b3a37868b6bf87c03c1 100644 (file)
@@ -48,6 +48,7 @@
 #include "access.h"
 #include "esfilter.h"
 #include "bouquet.h"
+#include "memoryinfo.h"
 
 static void service_data_timeout(void *aux);
 static void service_class_delete(struct idnode *self);
@@ -936,6 +937,13 @@ service_provider_name ( service_t *s )
   return NULL;
 }
 
+void
+service_memoryinfo ( service_t *s, int64_t *size )
+{
+  *size += sizeof(*s);
+  *size += tvh_strlen(s->s_nicename);
+}
+
 /**
  * Create and initialize a new service struct
  */
@@ -968,6 +976,7 @@ service_create0
   t->s_channel_number = service_channel_number;
   t->s_channel_name   = service_channel_name;
   t->s_provider_name  = service_provider_name;
+  t->s_memoryinfo     = service_memoryinfo;
   TAILQ_INIT(&t->s_components);
   TAILQ_INIT(&t->s_filt_components);
   t->s_last_pid = -1;
@@ -1483,9 +1492,36 @@ service_saver(void *aux)
  */
 pthread_t service_saver_tid;
 
+static void services_memoryinfo_update(memoryinfo_t *my)
+{
+  service_t *t;
+  int64_t size = 0, count = 0;
+
+  lock_assert(&global_lock);
+  TAILQ_FOREACH(t, &service_all, s_all_link) {
+    t->s_memoryinfo(t, &size);
+    count++;
+  }
+  TAILQ_FOREACH(t, &service_raw_all, s_all_link) {
+    t->s_memoryinfo(t, &size);
+    count++;
+  }
+  TAILQ_FOREACH(t, &service_raw_remove, s_all_link) {
+    t->s_memoryinfo(t, &size);
+    count++;
+  }
+  memoryinfo_update(my, size, count);
+}
+
+static memoryinfo_t services_memoryinfo = {
+  .my_name = "Services",
+  .my_update = services_memoryinfo_update
+};
+
 void
 service_init(void)
 {
+  memoryinfo_register(&services_memoryinfo);
   TAILQ_INIT(&pending_save_queue);
   TAILQ_INIT(&service_all);
   TAILQ_INIT(&service_raw_all);
@@ -1508,6 +1544,7 @@ service_done(void)
   pthread_mutex_lock(&global_lock);
   while ((t = TAILQ_FIRST(&service_raw_remove)) != NULL)
     service_destroy(t, 0);
+  memoryinfo_unregister(&services_memoryinfo);
   pthread_mutex_unlock(&global_lock);
 }
 
index 47ea5cda86a6663c22903003f474a3caf0c148b9..32bff5c6bfd9c5c108d47e3facd3b8b885f7897d 100644 (file)
@@ -330,6 +330,8 @@ typedef struct service {
 
   int (*s_satip_source)(struct service *t);
 
+  void (*s_memoryinfo)(struct service *t, int64_t *size);
+
   /**
    * Channel info
    */
@@ -623,6 +625,8 @@ int64_t     service_get_channel_number (service_t *s);
 const char *service_get_channel_icon (service_t *s);
 const char *service_get_channel_epgid (service_t *s);
 
+void service_memoryinfo (service_t *s, int64_t *size);
+
 void service_mapped (service_t *s);
 
 #endif // SERVICE_H__
index d5273b60a3247ab76846316de94742c6cfd1da3f..e6925091af71281b43f4ef79fb95a99a7dc86a4e 100644 (file)
@@ -55,11 +55,11 @@ streaming_message_data_size(streaming_message_t *sm)
   if (sm->sm_type == SMT_PACKET) {
     th_pkt_t *pkt = sm->sm_data;
     if (pkt && pkt->pkt_payload)
-      return pkt->pkt_payload->pb_size;
+      return pktbuf_len(pkt->pkt_payload);
   } else if (sm->sm_type == SMT_MPEGTS) {
     pktbuf_t *pkt_payload = sm->sm_data;
     if (pkt_payload)
-      return pkt_payload->pb_size;
+      return pktbuf_len(pkt_payload);
   }
   return 0;
 }
index 6780ba338d0400f916bd18f6ebe2e55fdd33a29f..a889bd35ccf1f78094805b4cd1354b75147e1f67 100644 (file)
@@ -485,11 +485,11 @@ subscription_input_direct(void *opauqe, streaming_message_t *sm)
     th_pkt_t *pkt = sm->sm_data;
     atomic_add(&s->ths_total_err, pkt->pkt_err);
     if (pkt->pkt_payload)
-      subscription_add_bytes_in(s, pkt->pkt_payload->pb_size);
+      subscription_add_bytes_in(s, pktbuf_len(pkt->pkt_payload));
   } else if(sm->sm_type == SMT_MPEGTS) {
     pktbuf_t *pb = sm->sm_data;
     atomic_add(&s->ths_total_err, pb->pb_err);
-    subscription_add_bytes_in(s, pb->pb_size);
+    subscription_add_bytes_in(s, pktbuf_len(pb));
   }
 
   /* Pass to output */
index ca9663a25ded385d74961d33f25fabd7807dc81b..9c25c3bc522478ecdb7f550c43ef9165ffaa25cf 100644 (file)
@@ -129,10 +129,10 @@ static ssize_t _read_pktbuf ( timeshift_file_t *tsf, int fd, pktbuf_t **pktbuf )
 
   /* Data */
   *pktbuf = pktbuf_alloc(NULL, sz);
-  r = _read_buf(tsf, fd, (*pktbuf)->pb_data, sz);
+  r = _read_buf(tsf, fd, pktbuf_ptr(*pktbuf), sz);
   if (r != sz) {
-    free((*pktbuf)->pb_data);
-    free(*pktbuf);
+    pktbuf_destroy(*pktbuf);
+    *pktbuf = NULL;
     return r < 0 ? -1 : 0;
   }
   cnt += r;
index 37eaa0d9fd3002021d632a6500d795debe6d3a50..9cd6221ebc8a218cf40886182449b9812a00a964 100644 (file)
@@ -143,7 +143,7 @@ static int _write_pktbuf ( timeshift_file_t *tsf, pktbuf_t *pktbuf )
   if (pktbuf) {
     ret = err = _write(tsf, &pktbuf->pb_size, sizeof(pktbuf->pb_size));
     if (err < 0) return err;
-    err = _write(tsf, pktbuf->pb_data, pktbuf->pb_size);
+    err = _write(tsf, pktbuf_ptr(pktbuf), pktbuf_len(pktbuf));
     if (err < 0) return err;
     ret += err;
   } else {
index 20ee1f60a55d1c0abe14b4054693dc5ffef9d538..8c067ed2733ad0c141bc94996601bbe5c221a45d 100644 (file)
@@ -255,6 +255,7 @@ void tasklet_disarm(tasklet_t *gti);
 /*
  * List / Queue header declarations
  */
+LIST_HEAD(memoryinfo_list, memoryinfo);
 LIST_HEAD(access_entry_list, access_entry);
 LIST_HEAD(th_subscription_list, th_subscription);
 LIST_HEAD(dvr_vfs_list, dvr_vfs);
@@ -671,6 +672,8 @@ extern void scopedunlock(pthread_mutex_t **mtxp);
      char *tvh_b = alloca(tvh_l + 1); \
      memcpy(tvh_b, n, tvh_l + 1); })
 
+#define tvh_strlen(s) ((s) ? strlen(s) : 0)
+
 #define tvh_strlcatf(buf, size, ptr, fmt...) \
   do { int __r = snprintf((buf) + ptr, (size) - ptr, fmt); \
        ptr = __r >= (size) - ptr ? (size) - 1 : ptr + __r; } while (0)
index d11bcdb5427039058729af02f4c5949d2041bcf7..9cb4db8a4238fef5b106b070fcb19d8cdee761bd 100644 (file)
@@ -580,7 +580,18 @@ function accessUpdate(o) {
             tvheadend.caclient(cp, 6);
 
         /* Debug */
-        tvheadend.tvhlog(cp, 7);
+        var dbg = new Ext.TabPanel({
+            tabIndex: 7,
+            activeTab: 0,
+            autoScroll: true,
+            title: _('Debugging'),
+            iconCls: 'debug',
+            items: []
+        });
+        tvheadend.tvhlog(dbg, 0);
+        tvheadend.memoryinfo(dbg, 1);
+
+        cp.add(dbg);
 
         /* Finish */
         tvheadend.rootTabPanel.add(cp);
index ac9d01f70ccfdccaa703d2cd5811053943519910..6fc7ce3a6637fb3d27b4a0733a449d1fb7a5c162 100644 (file)
@@ -14,7 +14,7 @@ tvheadend.tvhlog = function(panel, index) {
 
     tvheadend.idnode_simple(panel, {
         url: 'api/tvhlog/config',
-        title: _('Debugging'),
+        title: _('Configuration'),
         iconCls: 'debug',
         tabIndex: index,
         comet: 'tvhlog_conf',
@@ -30,3 +30,18 @@ tvheadend.tvhlog = function(panel, index) {
     });
 
 };
+
+tvheadend.memoryinfo = function(panel, index)
+{
+    tvheadend.idnode_grid(panel, {
+        url: 'api/memoryinfo',
+        titleS: _('Memory info entry'),
+        titleP: _('Memory info entries'),
+        iconCls: 'exclamation',
+        tabIndex: index,
+        readonly: true,
+        help: function() {
+            new tvheadend.help(_('Memory information entries'), 'config_memoryinfo.html');
+        }
+    });
+};