#include "slap.h"
+#ifdef USE_VALGRIND
+/* Get debugging help from Valgrind */
+#include <valgrind/memcheck.h>
+#define VGMEMP_MARK(m,s) VALGRIND_MAKE_MEM_NOACCESS(m,s)
+#define VGMEMP_CREATE(h,r,z) VALGRIND_CREATE_MEMPOOL(h,r,z)
+#define VGMEMP_TRIM(h,a,s) VALGRIND_MEMPOOL_TRIM(h,a,s)
+#define VGMEMP_ALLOC(h,a,s) VALGRIND_MEMPOOL_ALLOC(h,a,s)
+#define VGMEMP_CHANGE(h,a,b,s) VALGRIND_MEMPOOL_CHANGE(h,a,b,s)
+#else
+#define VGMEMP_MARK(m,s)
+#define VGMEMP_CREATE(h,r,z)
+#define VGMEMP_TRIM(h,a,s)
+#define VGMEMP_ALLOC(h,a,s)
+#define VGMEMP_CHANGE(h,a,b,s)
+#endif
+
/*
* This allocator returns temporary memory from a slab in a given memory
* context, aligned on a 2-int boundary. It cannot be used for data
#ifdef NO_THREADS
static struct slab_heap *slheap;
# define SET_MEMCTX(thrctx, memctx, sfree) ((void) (slheap = (memctx)))
-# define GET_MEMCTX(thrctx, memctxp) (*(memctxp) = slheap))
+# define GET_MEMCTX(thrctx, memctxp) (*(memctxp) = slheap)
#else
# define memctx_key ((void *) slap_sl_mem_init)
# define SET_MEMCTX(thrctx, memctx, kfree) \
struct slab_heap *sh;
ber_len_t size_shift;
struct slab_object *so;
+ char *base, *newptr;
enum { Base_offset = (unsigned) -sizeof(ber_len_t) % Align };
sh = GET_MEMCTX(thrctx, &memctx);
if ( sh && !new )
return sh;
- /* round up to doubleword boundary */
- size = (size + Align-1) & -Align;
+ /* Round up to doubleword boundary, then make room for initial
+ * padding, preserving expected available size for pool version */
+ size = ((size + Align-1) & -Align) + Base_offset;
if (!sh) {
sh = ch_malloc(sizeof(struct slab_heap));
- sh->sh_base = ch_malloc(size);
+ base = ch_malloc(size);
SET_MEMCTX(thrctx, sh, slap_sl_mem_destroy);
+ VGMEMP_MARK(base, size);
+ VGMEMP_CREATE(sh, 0, 0);
} else {
slap_sl_mem_destroy(NULL, sh);
- if ( size > (char *)sh->sh_end - (char *)sh->sh_base ) {
- void *newptr;
-
- newptr = ch_realloc( sh->sh_base, size );
+ base = sh->sh_base;
+ if (size > (ber_len_t) ((char *) sh->sh_end - base)) {
+ newptr = ch_realloc(base, size);
if ( newptr == NULL ) return NULL;
- sh->sh_base = newptr;
+ VGMEMP_CHANGE(sh, base, newptr, size);
+ base = newptr;
}
+ VGMEMP_TRIM(sh, sh->sh_base, 0);
}
- sh->sh_end = (char *) sh->sh_base + size;
+ sh->sh_base = base;
+ sh->sh_end = base + size;
+
+ /* Align (base + head of first block) == first returned block */
+ base += Base_offset;
+ size -= Base_offset;
sh->sh_stack = stack;
if (stack) {
- /* Align first returned block (sh_last + head) */
- sh->sh_last = (char *) sh->sh_base + Base_offset;
+ sh->sh_last = base;
} else {
int i, order = -1, order_end = -1;
}
so = LDAP_LIST_FIRST(&sh->sh_sopool);
LDAP_LIST_REMOVE(so, so_link);
- so->so_ptr = sh->sh_base;
+ so->so_ptr = base;
LDAP_LIST_INSERT_HEAD(&sh->sh_free[order-1], so, so_link);
memset(sh->sh_map[i], 0, nummaps);
}
}
+
return sh;
}
if (size < (ber_len_t) ((char *) sh->sh_end - (char *) sh->sh_last)) {
newptr = sh->sh_last;
sh->sh_last = (char *) sh->sh_last + size;
+ VGMEMP_ALLOC(sh, newptr, size);
*newptr++ = size;
return( (void *)newptr );
}
/* Mark it free: tail = size, head of next block |= 1 */
nextp[-1] = size;
nextp[0] |= 1;
+ /* We can't tell Valgrind about it yet, because we
+ * still need read/write access to this block for
+ * when we eventually get to reclaim it.
+ */
} else {
/* Reclaim freed block(s) off tail */
while (*p & 1) {
p = (ber_len_t *) ((char *) p - p[-1]);
}
sh->sh_last = p;
+ VGMEMP_TRIM(sh, sh->sh_base, sh->sh_last - sh->sh_base);
}
} else {