@@@ fltfmt mess
[mLib] / mem / sub.c
index 1abfedd..185be3a 100644 (file)
--- a/mem/sub.c
+++ b/mem/sub.c
@@ -56,6 +56,8 @@
 
 /*----- Header files ------------------------------------------------------*/
 
+#include "config.h"
+
 /* --- ANSI headers --- */
 
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 
+/* --- External headers --- */
+
+#ifdef HAVE_VALGRIND_VALGRIND_H
+#  include <valgrind/valgrind.h>
+#  include <valgrind/memcheck.h>
+#  define VG(x) x
+#else
+#  define VG(x)
+#endif
+
 /* --- Local headers --- */
 
 #include "arena.h"
 
 /* #define SUBARENA_TRIVIAL */
 
+#define REDZONE_SIZE (2*SUB_GRANULE)
+
 /*----- Static variables --------------------------------------------------*/
 
 static size_t sizes[SUB_BINS];
+VG( static unsigned flags; )
+#define SF_VALGRIND 1u
 
 /*----- Global variables --------------------------------------------------*/
 
@@ -89,6 +105,13 @@ typedef struct sub_link {
   size_t sz;
 } sub_link;
 
+#else
+
+union sub_header {
+  void *next;
+  union align _a;
+};
+
 #endif
 
 /*----- Main code ---------------------------------------------------------*/
@@ -110,10 +133,10 @@ void subarena_create(subarena *s, arena *a)
   s->bin[0] = 0;
 #else
   size_t i;
-  if (!sizes[1])
-    sub_init();
-  for (i = 0; i < SUB_BINS; i++)
-    s->bin[i] = 0;
+
+  if (!sizes[1]) sub_init();
+  for (i = 0; i < SUB_BINS; i++) s->bin[i] = 0;
+  VG( VALGRIND_CREATE_MEMPOOL(s, REDZONE_SIZE, 0); )
 #endif
   s->a = a;
 }
@@ -143,16 +166,10 @@ void subarena_destroy(subarena *s)
 
 #else
 
-  size_t i;
-  for (i = 0; i < SUB_BINS; i++) {
-    void *p = s->bin[i];
-    while (p) {
-      void *q = p;
-      p = *(void **)q;
-      A_FREE(s->a, q);
-    }
-    s->bin[i] = 0;
-  }
+  union sub_header *p, *q;
+
+  for (p = s->bin[0]; p; p = q) { q = p->next; A_FREE(s->a, p); }
+  VG( VALGRIND_DESTROY_MEMPOOL(s); )
 
 #endif
 }
@@ -176,67 +193,53 @@ void *subarena_alloc(subarena *s, size_t sz)
   sub_link *l;
   void *p;
 
-  if (!s->a)
-    subarena_create(s, arena_global);
+  if (!s->a) subarena_create(s, arena_global);
 
-  if ((l = a_alloc(s->a, sizeof(*l))) == 0)
-    return (0);
-  if ((p = a_alloc(s->a, sz)) == 0) {
-    a_free(s->a, l);
-    return (0);
-  }
-  l->p = p;
-  l->sz = sz;
-  l->next = s->bin[0];
-  s->bin[0] = l;
+  if ((l = a_alloc(s->a, sizeof(*l))) == 0) return (0);
+  if ((p = a_alloc(s->a, sz)) == 0) { a_free(s->a, l); return (0); }
+  l->p = p; l->sz = sz; l->next = s->bin[0]; s->bin[0] = l;
   return (p);
 
 #else
 
-  int bin;
-  void *p;
+  unsigned char *p, *q;
+  union sub_header *h;
+  size_t bin, chsz, redsz;
 
   /* --- Ensure that everything is initialized --- */
 
-  if (!s->a)
-    subarena_create(s, arena_global);
+  if (!s->a) subarena_create(s, arena_global);
 
   /* --- Handle oversize blocks --- */
 
   bin = SUB_BIN(sz);
   if (bin >= SUB_BINS) {
-    void *p = A_ALLOC(s->a, sz);
-    if (!p)
-      THROW(EXC_NOMEM);
+    p = A_ALLOC(s->a, sz); if (!p) THROW(EXC_NOMEM);
     return (p);
   }
 
   /* --- If the bin is empty, find some memory --- */
 
   if (!s->bin[bin]) {
-    char *p, *q;
-
-    p = A_ALLOC(s->a, sizes[bin]);
-    if (!p)
-      THROW(EXC_NOMEM);
-    q = p + sizes[bin];
-
-    sz = SUB_BINSZ(bin);
-
-    q -= sz;
-    *(void **)q = 0;
-
-    while (q > p) {
-      q -= sz;
-      *(void **)q = q + sz;
-    }
-
-    s->bin[bin] = p;
+    redsz = 0; VG( if (flags&SF_VALGRIND) redsz = REDZONE_SIZE; )
+    chsz = SUB_BINSZ(bin) + redsz;
+    h = A_ALLOC(s->a, sizes[bin]); if (!h) THROW(EXC_NOMEM);
+    h->next = s->bin[0]; s->bin[0] = h;
+    p = (unsigned char *)(h + 1);
+    q = (unsigned char *)h + sizes[bin] - redsz - chsz; *(void **)q = 0;
+    while (q > p) { q -= chsz; *(void **)q = q + chsz; }
+    s->bin[bin] = q;
+    VG( VALGRIND_MAKE_MEM_NOACCESS(p, sizes[bin]); )
   }
 
   /* --- Extract the first block in the list --- */
 
   p = s->bin[bin];
+  VG( if (flags&SF_VALGRIND) {
+       VALGRIND_MAKE_MEM_DEFINED(p, sizeof(void *));
+       s->bin[bin] = *(void **)p;
+       VALGRIND_MEMPOOL_ALLOC(s, p, sz);
+      } else )
   s->bin[bin] = *(void **)p;
   return (p);
 
@@ -260,25 +263,20 @@ void subarena_free(subarena *s, void *p, size_t sz)
 
   sub_link *lh = s->bin[0], **l, *ll;
 
-  for (l = &lh; *l && (*l)->p != p; l = &(*l)->next)
-    ;
-  ll = *l;
-  assert(ll);
-  assert(ll->sz == sz);
+  for (l = &lh; *l && (*l)->p != p; l = &(*l)->next) ;
+  ll = *l; assert(ll); assert(ll->sz == sz);
   *l = ll->next;
-  a_free(s->a, ll);
-  a_free(s->a, p);
-  s->bin[0] = lh;
+  a_free(s->a, ll); a_free(s->a, p); s->bin[0] = lh;
 
 #else
 
-  int bin = SUB_BIN(sz);
+  size_t bin = SUB_BIN(sz);
 
   if (bin >= SUB_BINS)
     A_FREE(s->a, p);
   else {
-    *(void **)p = s->bin[bin];
-    s->bin[bin] = p;
+    *(void **)p = s->bin[bin]; s->bin[bin] = p;
+    VG( if (flags&SF_VALGRIND) VALGRIND_MEMPOOL_FREE(s, p); )
   }
 
 #endif
@@ -321,13 +319,21 @@ void (sub_free)(void *p, size_t sz) { sub_free(p, sz); }
 void sub_init(void)
 {
 #ifndef SUBARENA_TRIVIAL
+  size_t n, sz;
   int i;
 
+  /* Find out if we're running under Valgrind --- */
+
+  VG( if (RUNNING_ON_VALGRIND) flags |= SF_VALGRIND; )
+
   /* --- Initialize the sizes bins --- */
 
   for (i = 1; i < SUB_BINS; i++) {
-    sizes[i] = ((SUB_CHUNK + SUB_BINSZ(i) - 1) /
-                    SUB_BINSZ(i) * SUB_BINSZ(i));
+    sz = SUB_BINSZ(i);
+    n = (SUB_CHUNK + sz - 1)/sz;
+    sz = sizeof(union sub_header) + n*sz;
+    VG( if (flags&SF_VALGRIND) sz += (n + 1)*REDZONE_SIZE; )
+    sizes[i] = sz;
   }
 #endif
 }