/* nsmalloc: Simple pooled malloc() thing. */
#include <stdlib.h>
-#include <stdio.h>
-#include <math.h>
+#include <string.h>
+#include <assert.h>
#include "nsmalloc.h"
#define __NSMALLOC_C
#undef __NSMALLOC_H
#include "nsmalloc.h"
+#include "../lib/valgrind.h"
+#include "../lib/memcheck.h"
#include "../core/hooks.h"
#include "../core/error.h"
-void *nsmalloc(unsigned int poolid, size_t size);
-void nsfree(unsigned int poolid, void *ptr);
-void nsfreeall(unsigned int poolid);
-
-struct nsminfo {
- struct nsminfo *next;
- struct nsminfo *prev;
-
- size_t size;
- char data[];
-};
-
-struct nsmpool {
- struct nsminfo first;
-
- unsigned long count;
- size_t size;
-};
-
-struct nsmpool pools[MAXPOOL];
-
-void nsmstats(int hookhum, void *arg);
-
-void initnsmalloc(void) {
- registerhook(HOOK_CORE_STATSREQUEST, &nsmstats);
-}
+struct nsmpool nsmpools[MAXPOOL];
void *nsmalloc(unsigned int poolid, size_t size) {
struct nsminfo *nsmp;
if (!nsmp)
return NULL;
-
+
+ VALGRIND_CREATE_MEMPOOL(nsmp, 0, 0);
+
nsmp->size=size;
- pools[poolid].size+=size;
- pools[poolid].count++;
+ nsmpools[poolid].size+=size;
+ nsmpools[poolid].count++;
+
+ if (nsmpools[poolid].blocks) {
+ nsmpools[poolid].blocks->prev = nsmp;
+ }
+ nsmp->next=nsmpools[poolid].blocks;
+ nsmp->prev=NULL;
+ nsmpools[poolid].blocks=nsmp;
+
+ VALGRIND_MEMPOOL_ALLOC(nsmp, nsmp->data, nsmp->size);
- nsmp->next=pools[poolid].first.next;
- nsmp->prev=&pools[poolid].first;
- if (pools[poolid].first.next)
- pools[poolid].first.next->prev=nsmp;
- pools[poolid].first.next=nsmp;
+ nsmp->redzone = REDZONE_MAGIC;
+ VALGRIND_MAKE_MEM_NOACCESS(&nsmp->redzone, sizeof(nsmp->redzone));
return (void *)nsmp->data;
}
-/* we dump core on ptr == NULL */
+void *nscalloc(unsigned int poolid, size_t nmemb, size_t size) {
+ size_t total = nmemb * size;
+ void *m;
+
+ m = nsmalloc(poolid, total);
+ if(!m)
+ return NULL;
+
+ memset(m, 0, total);
+
+ return m;
+}
+
void nsfree(unsigned int poolid, void *ptr) {
struct nsminfo *nsmp;
- if (poolid >= MAXPOOL)
+ if (!ptr || poolid >= MAXPOOL)
return;
/* evil */
nsmp=(struct nsminfo*)ptr - 1;
- /* always set as we have a sentinel */
- nsmp->prev->next=nsmp->next;
- if (nsmp->next)
- nsmp->next->prev=nsmp->prev;
+ VALGRIND_MAKE_MEM_DEFINED(&nsmp->redzone, sizeof(nsmp->redzone));
+ assert(nsmp->redzone == REDZONE_MAGIC);
+
+ if (nsmp->prev) {
+ nsmp->prev->next = nsmp->next;
+ } else
+ nsmpools[poolid].blocks = NULL;
+
+ if (nsmp->next) {
+ nsmp->next->prev = nsmp->prev;
+ }
- pools[poolid].size-=nsmp->size;
- pools[poolid].count--;
+ nsmpools[poolid].size-=nsmp->size;
+ nsmpools[poolid].count--;
+ VALGRIND_MEMPOOL_FREE(nsmp, nsmp->data);
free(nsmp);
+ VALGRIND_DESTROY_MEMPOOL(nsmp);
+
return;
}
/* evil */
nsmp=(struct nsminfo *)ptr - 1;
+ VALGRIND_MAKE_MEM_DEFINED(nsmp, sizeof(struct nsminfo));
+
if (size == nsmp->size)
return (void *)nsmp->data;
if (!nsmpn)
return NULL;
- pools[poolid].size+=size-nsmpn->size;
+ VALGRIND_MOVE_MEMPOOL(nsmp, nsmpn);
+
+ nsmpools[poolid].size+=size-nsmpn->size;
nsmpn->size=size;
- /* always set as we have a sentinel */
- nsmpn->prev->next=nsmpn;
+ if (nsmpn->prev) {
+ nsmpn->prev->next=nsmpn;
+ } else
+ nsmpools[poolid].blocks = nsmpn;
- if (nsmpn->next)
+ if (nsmpn->next) {
nsmpn->next->prev=nsmpn;
+ }
+
+ VALGRIND_MEMPOOL_CHANGE(nsmpn, nsmp->data, nsmpn->data, nsmpn->size);
return (void *)nsmpn->data;
}
if (poolid >= MAXPOOL)
return;
- for (nsmp=pools[poolid].first.next;nsmp;nsmp=nnsmp) {
+ for (nsmp=nsmpools[poolid].blocks;nsmp;nsmp=nnsmp) {
nnsmp=nsmp->next;
+ VALGRIND_MEMPOOL_FREE(nsmp, nsmp->data);
free(nsmp);
+ VALGRIND_DESTROY_MEMPOOL(nsmp);
}
- pools[poolid].first.next=NULL;
- pools[poolid].size=0;
- pools[poolid].count=0;
+ nsmpools[poolid].blocks=NULL;
+ nsmpools[poolid].size=0;
+ nsmpools[poolid].count=0;
}
void nscheckfreeall(unsigned int poolid) {
if (poolid >= MAXPOOL)
return;
- if (pools[poolid].first.next) {
- Error("core",ERR_INFO,"nsmalloc: Blocks still allocated in pool #%d (%s): %lub, %lu items",poolid,poolnames[poolid]?poolnames[poolid]:"??",pools[poolid].size,pools[poolid].count);
+ if (nsmpools[poolid].blocks) {
+ Error("core",ERR_INFO,"nsmalloc: Blocks still allocated in pool #%d (%s): %zub, %lu items",poolid,nsmpoolnames[poolid]?nsmpoolnames[poolid]:"??",nsmpools[poolid].size,nsmpools[poolid].count);
nsfreeall(poolid);
}
}
+void nsinit(void) {
+ memset(nsmpools, 0, sizeof(nsmpools));
+}
+
void nsexit(void) {
unsigned int i;
for (i=0;i<MAXPOOL;i++)
- nscheckfreeall(i);
-}
-
-static char *formatmbuf(unsigned long count, size_t size, size_t realsize) {
- static char buf[1024];
-
- snprintf(buf, sizeof(buf), "%lu items, %luKb allocated for %luKb space, %luKb (%0.2f%%) overhead", count, (unsigned long)size / 1024, (unsigned long)realsize / 1024, (unsigned long)(realsize - size) / 1024, (double)(realsize - size) / (double)size * 100);
- return buf;
+ nsfreeall(i);
}
-void nsmstats(int hookhum, void *arg) {
- int i;
- char buf[1024], header[1024];
- unsigned long totalcount = 0;
- size_t totalsize = 0, totalrealsize = 0;
- long level = (long)arg;
-
- for (i=0;i<MAXPOOL;i++) {
- struct nsmpool *pool=&pools[i];
- size_t realsize;
-
- if (!pool->count)
- continue;
-
- realsize=pool->size + pool->count * sizeof(struct nsminfo) + sizeof(struct nsmpool);
-
- snprintf(header, sizeof(header), "NSMalloc: pool %2d (%s): ", i, poolnames[i]?poolnames[i]:"??");
-
- if(level > 10) {
- snprintf(buf, sizeof(buf), "%s %s", header, formatmbuf(pool->count, pool->size, realsize));
- triggerhook(HOOK_CORE_STATSREPLY, buf);
- }
-
- totalsize+=pool->size;
- totalrealsize+=realsize;
- totalcount+=pool->count;
-
- if(level > 100) {
- struct nsminfo *np = pool->first.next;
- double mean = (double)pool->size / pool->count, variance;
- unsigned long long int sumsq = 0;
-
- for (np=pool->first.next;np;np=np->next)
- sumsq+=np->size * np->size;
-
- variance=(double)sumsq / pool->count - mean * mean;
-
- snprintf(buf, sizeof(buf), "%s allocation sumsq: %llu mean: %.2f variance: %.2f stddev: %.2f", header, sumsq, mean, variance, sqrtf(variance));
- triggerhook(HOOK_CORE_STATSREPLY, buf);
- }
- }
-
- snprintf(buf, sizeof(buf), "NSMalloc: pool totals: %s", formatmbuf(totalcount, totalsize, totalrealsize));
- triggerhook(HOOK_CORE_STATSREPLY, buf);
-}