/*----- 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 --------------------------------------------------*/
size_t sz;
} sub_link;
+#else
+
+union sub_header {
+ void *next;
+ union align _a;
+};
+
#endif
/*----- Main code ---------------------------------------------------------*/
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;
}
#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
}
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);
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
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
}