13e12c5d1SDavid du Colombier #include "u.h"
23e12c5d1SDavid du Colombier #include "../port/lib.h"
33e12c5d1SDavid du Colombier #include "mem.h"
43e12c5d1SDavid du Colombier #include "dat.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier #include "error.h"
77dd7cddfSDavid du Colombier #include <pool.h>
83e12c5d1SDavid du Colombier
97dd7cddfSDavid du Colombier static void poolprint(Pool*, char*, ...);
107dd7cddfSDavid du Colombier static void ppanic(Pool*, char*, ...);
117dd7cddfSDavid du Colombier static void plock(Pool*);
127dd7cddfSDavid du Colombier static void punlock(Pool*);
137dd7cddfSDavid du Colombier
147dd7cddfSDavid du Colombier typedef struct Private Private;
157dd7cddfSDavid du Colombier struct Private {
167dd7cddfSDavid du Colombier Lock lk;
177dd7cddfSDavid du Colombier char msg[256]; /* a rock for messages to be printed at unlock */
187dd7cddfSDavid du Colombier };
197dd7cddfSDavid du Colombier
207dd7cddfSDavid du Colombier static Private pmainpriv;
217dd7cddfSDavid du Colombier static Pool pmainmem = {
227dd7cddfSDavid du Colombier .name= "Main",
237dd7cddfSDavid du Colombier .maxsize= 4*1024*1024,
247dd7cddfSDavid du Colombier .minarena= 128*1024,
257dd7cddfSDavid du Colombier .quantum= 32,
267dd7cddfSDavid du Colombier .alloc= xalloc,
277dd7cddfSDavid du Colombier .merge= xmerge,
287dd7cddfSDavid du Colombier .flags= POOL_TOLERANCE,
297dd7cddfSDavid du Colombier
307dd7cddfSDavid du Colombier .lock= plock,
317dd7cddfSDavid du Colombier .unlock= punlock,
327dd7cddfSDavid du Colombier .print= poolprint,
337dd7cddfSDavid du Colombier .panic= ppanic,
347dd7cddfSDavid du Colombier
357dd7cddfSDavid du Colombier .private= &pmainpriv,
367dd7cddfSDavid du Colombier };
377dd7cddfSDavid du Colombier
387dd7cddfSDavid du Colombier static Private pimagpriv;
397dd7cddfSDavid du Colombier static Pool pimagmem = {
407dd7cddfSDavid du Colombier .name= "Image",
417dd7cddfSDavid du Colombier .maxsize= 16*1024*1024,
427dd7cddfSDavid du Colombier .minarena= 2*1024*1024,
437dd7cddfSDavid du Colombier .quantum= 32,
447dd7cddfSDavid du Colombier .alloc= xalloc,
457dd7cddfSDavid du Colombier .merge= xmerge,
467dd7cddfSDavid du Colombier .flags= 0,
477dd7cddfSDavid du Colombier
487dd7cddfSDavid du Colombier .lock= plock,
497dd7cddfSDavid du Colombier .unlock= punlock,
507dd7cddfSDavid du Colombier .print= poolprint,
517dd7cddfSDavid du Colombier .panic= ppanic,
527dd7cddfSDavid du Colombier
537dd7cddfSDavid du Colombier .private= &pimagpriv,
547dd7cddfSDavid du Colombier };
557dd7cddfSDavid du Colombier
567dd7cddfSDavid du Colombier Pool* mainmem = &pmainmem;
577dd7cddfSDavid du Colombier Pool* imagmem = &pimagmem;
583e12c5d1SDavid du Colombier
593e12c5d1SDavid du Colombier /*
607dd7cddfSDavid du Colombier * because we can't print while we're holding the locks,
617dd7cddfSDavid du Colombier * we have the save the message and print it once we let go.
623e12c5d1SDavid du Colombier */
637dd7cddfSDavid du Colombier static void
poolprint(Pool * p,char * fmt,...)647dd7cddfSDavid du Colombier poolprint(Pool *p, char *fmt, ...)
653e12c5d1SDavid du Colombier {
667dd7cddfSDavid du Colombier va_list v;
677dd7cddfSDavid du Colombier Private *pv;
68219b2ee8SDavid du Colombier
697dd7cddfSDavid du Colombier pv = p->private;
707dd7cddfSDavid du Colombier va_start(v, fmt);
719a747e4fSDavid du Colombier vseprint(pv->msg+strlen(pv->msg), pv->msg+sizeof pv->msg, fmt, v);
727dd7cddfSDavid du Colombier va_end(v);
737dd7cddfSDavid du Colombier }
743e12c5d1SDavid du Colombier
757dd7cddfSDavid du Colombier static void
ppanic(Pool * p,char * fmt,...)767dd7cddfSDavid du Colombier ppanic(Pool *p, char *fmt, ...)
773e12c5d1SDavid du Colombier {
787dd7cddfSDavid du Colombier va_list v;
797dd7cddfSDavid du Colombier Private *pv;
807dd7cddfSDavid du Colombier char msg[sizeof pv->msg];
813e12c5d1SDavid du Colombier
827dd7cddfSDavid du Colombier pv = p->private;
837dd7cddfSDavid du Colombier va_start(v, fmt);
849a747e4fSDavid du Colombier vseprint(pv->msg+strlen(pv->msg), pv->msg+sizeof pv->msg, fmt, v);
857dd7cddfSDavid du Colombier va_end(v);
867dd7cddfSDavid du Colombier memmove(msg, pv->msg, sizeof msg);
877dd7cddfSDavid du Colombier iunlock(&pv->lk);
887dd7cddfSDavid du Colombier panic("%s", msg);
897dd7cddfSDavid du Colombier }
907dd7cddfSDavid du Colombier
917dd7cddfSDavid du Colombier static void
plock(Pool * p)927dd7cddfSDavid du Colombier plock(Pool *p)
933e12c5d1SDavid du Colombier {
947dd7cddfSDavid du Colombier Private *pv;
953e12c5d1SDavid du Colombier
967dd7cddfSDavid du Colombier pv = p->private;
977dd7cddfSDavid du Colombier ilock(&pv->lk);
98*2cca75a1SDavid du Colombier pv->lk.pc = getcallerpc(&p);
997dd7cddfSDavid du Colombier pv->msg[0] = 0;
1007dd7cddfSDavid du Colombier }
1017dd7cddfSDavid du Colombier
1027dd7cddfSDavid du Colombier static void
punlock(Pool * p)1037dd7cddfSDavid du Colombier punlock(Pool *p)
1043e12c5d1SDavid du Colombier {
1057dd7cddfSDavid du Colombier Private *pv;
1067dd7cddfSDavid du Colombier char msg[sizeof pv->msg];
1073e12c5d1SDavid du Colombier
1087dd7cddfSDavid du Colombier pv = p->private;
1097dd7cddfSDavid du Colombier if(pv->msg[0] == 0){
1107dd7cddfSDavid du Colombier iunlock(&pv->lk);
1117dd7cddfSDavid du Colombier return;
1127dd7cddfSDavid du Colombier }
1133e12c5d1SDavid du Colombier
1147dd7cddfSDavid du Colombier memmove(msg, pv->msg, sizeof msg);
1157dd7cddfSDavid du Colombier iunlock(&pv->lk);
116e288d156SDavid du Colombier iprint("%.*s", sizeof pv->msg, msg);
1177dd7cddfSDavid du Colombier }
1183e12c5d1SDavid du Colombier
1193e12c5d1SDavid du Colombier void
poolsummary(Pool * p)1207dd7cddfSDavid du Colombier poolsummary(Pool *p)
1213e12c5d1SDavid du Colombier {
1227dd7cddfSDavid du Colombier print("%s max %lud cur %lud free %lud alloc %lud\n", p->name,
1237dd7cddfSDavid du Colombier p->maxsize, p->cursize, p->curfree, p->curalloc);
1243e12c5d1SDavid du Colombier }
1253e12c5d1SDavid du Colombier
1267dd7cddfSDavid du Colombier void
mallocsummary(void)1277dd7cddfSDavid du Colombier mallocsummary(void)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier poolsummary(mainmem);
1307dd7cddfSDavid du Colombier poolsummary(imagmem);
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier
1337dd7cddfSDavid du Colombier /* everything from here down should be the same in libc, libdebugmalloc, and the kernel */
1347dd7cddfSDavid du Colombier /* - except the code for malloc(), which alternately doesn't clear or does. */
1357dd7cddfSDavid du Colombier /* - except the code for smalloc(), which lives only in the kernel. */
1367dd7cddfSDavid du Colombier
1373e12c5d1SDavid du Colombier /*
1387dd7cddfSDavid du Colombier * Npadlong is the number of 32-bit longs to leave at the beginning of
1397dd7cddfSDavid du Colombier * each allocated buffer for our own bookkeeping. We return to the callers
1407dd7cddfSDavid du Colombier * a pointer that points immediately after our bookkeeping area. Incoming pointers
1417dd7cddfSDavid du Colombier * must be decremented by that much, and outgoing pointers incremented.
1427dd7cddfSDavid du Colombier * The malloc tag is stored at MallocOffset from the beginning of the block,
1437dd7cddfSDavid du Colombier * and the realloc tag at ReallocOffset. The offsets are from the true beginning
1447dd7cddfSDavid du Colombier * of the block, not the beginning the caller sees.
1457dd7cddfSDavid du Colombier *
1467dd7cddfSDavid du Colombier * The extra if(Npadlong != 0) in various places is a hint for the compiler to
1477dd7cddfSDavid du Colombier * compile out function calls that would otherwise be no-ops.
1483e12c5d1SDavid du Colombier */
1493e12c5d1SDavid du Colombier
1507dd7cddfSDavid du Colombier /* non tracing
1517dd7cddfSDavid du Colombier *
1527dd7cddfSDavid du Colombier enum {
1537dd7cddfSDavid du Colombier Npadlong = 0,
1547dd7cddfSDavid du Colombier MallocOffset = 0,
1557dd7cddfSDavid du Colombier ReallocOffset = 0,
1567dd7cddfSDavid du Colombier };
1577dd7cddfSDavid du Colombier *
1587dd7cddfSDavid du Colombier */
1593e12c5d1SDavid du Colombier
1607dd7cddfSDavid du Colombier /* tracing */
1617dd7cddfSDavid du Colombier enum {
1627dd7cddfSDavid du Colombier Npadlong = 2,
1637dd7cddfSDavid du Colombier MallocOffset = 0,
1647dd7cddfSDavid du Colombier ReallocOffset = 1
1657dd7cddfSDavid du Colombier };
1663e12c5d1SDavid du Colombier
1673e12c5d1SDavid du Colombier
1683e12c5d1SDavid du Colombier void*
smalloc(ulong size)1697dd7cddfSDavid du Colombier smalloc(ulong size)
1703e12c5d1SDavid du Colombier {
1717dd7cddfSDavid du Colombier void *v;
1723e12c5d1SDavid du Colombier
1737dd7cddfSDavid du Colombier for(;;) {
1747dd7cddfSDavid du Colombier v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
1757dd7cddfSDavid du Colombier if(v != nil)
1763e12c5d1SDavid du Colombier break;
1777dd7cddfSDavid du Colombier tsleep(&up->sleep, return0, 0, 100);
1783e12c5d1SDavid du Colombier }
1797dd7cddfSDavid du Colombier if(Npadlong){
1807dd7cddfSDavid du Colombier v = (ulong*)v+Npadlong;
1817dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&size));
1823e12c5d1SDavid du Colombier }
1837dd7cddfSDavid du Colombier memset(v, 0, size);
1847dd7cddfSDavid du Colombier return v;
185219b2ee8SDavid du Colombier }
186219b2ee8SDavid du Colombier
1873e12c5d1SDavid du Colombier void*
malloc(ulong size)1883e12c5d1SDavid du Colombier malloc(ulong size)
1893e12c5d1SDavid du Colombier {
1907dd7cddfSDavid du Colombier void *v;
1913e12c5d1SDavid du Colombier
1927dd7cddfSDavid du Colombier v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
1939a747e4fSDavid du Colombier if(v == nil)
1949a747e4fSDavid du Colombier return nil;
1959a747e4fSDavid du Colombier if(Npadlong){
1967dd7cddfSDavid du Colombier v = (ulong*)v+Npadlong;
1977dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&size));
1987dd7cddfSDavid du Colombier setrealloctag(v, 0);
199219b2ee8SDavid du Colombier }
2009a747e4fSDavid du Colombier memset(v, 0, size);
2017dd7cddfSDavid du Colombier return v;
2023e12c5d1SDavid du Colombier }
2033e12c5d1SDavid du Colombier
2043e12c5d1SDavid du Colombier void*
mallocz(ulong size,int clr)2057dd7cddfSDavid du Colombier mallocz(ulong size, int clr)
2063e12c5d1SDavid du Colombier {
2077dd7cddfSDavid du Colombier void *v;
2083e12c5d1SDavid du Colombier
2097dd7cddfSDavid du Colombier v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
2107dd7cddfSDavid du Colombier if(Npadlong && v != nil){
2117dd7cddfSDavid du Colombier v = (ulong*)v+Npadlong;
2127dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&size));
2137dd7cddfSDavid du Colombier setrealloctag(v, 0);
214219b2ee8SDavid du Colombier }
2157dd7cddfSDavid du Colombier if(clr && v != nil)
2167dd7cddfSDavid du Colombier memset(v, 0, size);
2177dd7cddfSDavid du Colombier return v;
2183e12c5d1SDavid du Colombier }
2193e12c5d1SDavid du Colombier
2205243b8d1SDavid du Colombier void*
mallocalign(ulong size,ulong align,long offset,ulong span)2215243b8d1SDavid du Colombier mallocalign(ulong size, ulong align, long offset, ulong span)
2225243b8d1SDavid du Colombier {
2235243b8d1SDavid du Colombier void *v;
2245243b8d1SDavid du Colombier
2255243b8d1SDavid du Colombier v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span);
2265243b8d1SDavid du Colombier if(Npadlong && v != nil){
2275243b8d1SDavid du Colombier v = (ulong*)v+Npadlong;
2285243b8d1SDavid du Colombier setmalloctag(v, getcallerpc(&size));
2295243b8d1SDavid du Colombier setrealloctag(v, 0);
2305243b8d1SDavid du Colombier }
231d917ddf4SDavid du Colombier if(v)
232d917ddf4SDavid du Colombier memset(v, 0, size);
2335243b8d1SDavid du Colombier return v;
2345243b8d1SDavid du Colombier }
2355243b8d1SDavid du Colombier
2363e12c5d1SDavid du Colombier void
free(void * v)2377dd7cddfSDavid du Colombier free(void *v)
2383e12c5d1SDavid du Colombier {
2397dd7cddfSDavid du Colombier if(v != nil)
2407dd7cddfSDavid du Colombier poolfree(mainmem, (ulong*)v-Npadlong);
2417dd7cddfSDavid du Colombier }
2423e12c5d1SDavid du Colombier
2437dd7cddfSDavid du Colombier void*
realloc(void * v,ulong size)2447dd7cddfSDavid du Colombier realloc(void *v, ulong size)
2457dd7cddfSDavid du Colombier {
2467dd7cddfSDavid du Colombier void *nv;
247219b2ee8SDavid du Colombier
2487dd7cddfSDavid du Colombier if(v != nil)
2497dd7cddfSDavid du Colombier v = (ulong*)v-Npadlong;
2507dd7cddfSDavid du Colombier if(Npadlong !=0 && size != 0)
2517dd7cddfSDavid du Colombier size += Npadlong*sizeof(ulong);
2527dd7cddfSDavid du Colombier
2537dd7cddfSDavid du Colombier if(nv = poolrealloc(mainmem, v, size)){
2547dd7cddfSDavid du Colombier nv = (ulong*)nv+Npadlong;
2557dd7cddfSDavid du Colombier setrealloctag(nv, getcallerpc(&v));
2567dd7cddfSDavid du Colombier if(v == nil)
2577dd7cddfSDavid du Colombier setmalloctag(nv, getcallerpc(&v));
258219b2ee8SDavid du Colombier }
2597dd7cddfSDavid du Colombier return nv;
260219b2ee8SDavid du Colombier }
2617dd7cddfSDavid du Colombier
2627dd7cddfSDavid du Colombier ulong
msize(void * v)2637dd7cddfSDavid du Colombier msize(void *v)
2647dd7cddfSDavid du Colombier {
2657dd7cddfSDavid du Colombier return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
266219b2ee8SDavid du Colombier }
2677dd7cddfSDavid du Colombier
2687dd7cddfSDavid du Colombier void*
calloc(ulong n,ulong szelem)2697dd7cddfSDavid du Colombier calloc(ulong n, ulong szelem)
2707dd7cddfSDavid du Colombier {
2717dd7cddfSDavid du Colombier void *v;
2727dd7cddfSDavid du Colombier if(v = mallocz(n*szelem, 1))
2737dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&n));
2747dd7cddfSDavid du Colombier return v;
2753e12c5d1SDavid du Colombier }
2763e12c5d1SDavid du Colombier
2773e12c5d1SDavid du Colombier void
setmalloctag(void * v,ulong pc)2787dd7cddfSDavid du Colombier setmalloctag(void *v, ulong pc)
2793e12c5d1SDavid du Colombier {
2807dd7cddfSDavid du Colombier ulong *u;
2817dd7cddfSDavid du Colombier USED(v, pc);
2827dd7cddfSDavid du Colombier if(Npadlong <= MallocOffset || v == nil)
2837dd7cddfSDavid du Colombier return;
2847dd7cddfSDavid du Colombier u = v;
2857dd7cddfSDavid du Colombier u[-Npadlong+MallocOffset] = pc;
2863e12c5d1SDavid du Colombier }
2877dd7cddfSDavid du Colombier
2887dd7cddfSDavid du Colombier void
setrealloctag(void * v,ulong pc)2897dd7cddfSDavid du Colombier setrealloctag(void *v, ulong pc)
2907dd7cddfSDavid du Colombier {
2917dd7cddfSDavid du Colombier ulong *u;
2927dd7cddfSDavid du Colombier USED(v, pc);
2937dd7cddfSDavid du Colombier if(Npadlong <= ReallocOffset || v == nil)
2947dd7cddfSDavid du Colombier return;
2957dd7cddfSDavid du Colombier u = v;
2967dd7cddfSDavid du Colombier u[-Npadlong+ReallocOffset] = pc;
2973e12c5d1SDavid du Colombier }
2987dd7cddfSDavid du Colombier
2997dd7cddfSDavid du Colombier ulong
getmalloctag(void * v)3007dd7cddfSDavid du Colombier getmalloctag(void *v)
3017dd7cddfSDavid du Colombier {
3027dd7cddfSDavid du Colombier USED(v);
3037dd7cddfSDavid du Colombier if(Npadlong <= MallocOffset)
3047dd7cddfSDavid du Colombier return ~0;
3057dd7cddfSDavid du Colombier return ((ulong*)v)[-Npadlong+MallocOffset];
3067dd7cddfSDavid du Colombier }
3077dd7cddfSDavid du Colombier
3087dd7cddfSDavid du Colombier ulong
getrealloctag(void * v)3097dd7cddfSDavid du Colombier getrealloctag(void *v)
3107dd7cddfSDavid du Colombier {
3117dd7cddfSDavid du Colombier USED(v);
3127dd7cddfSDavid du Colombier if(Npadlong <= ReallocOffset)
3137dd7cddfSDavid du Colombier return ((ulong*)v)[-Npadlong+ReallocOffset];
3147dd7cddfSDavid du Colombier return ~0;
3153e12c5d1SDavid du Colombier }
316