xref: /plan9-contrib/sys/src/9/port/alloc.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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"
73e12c5d1SDavid du Colombier 
83e12c5d1SDavid du Colombier 
93e12c5d1SDavid du Colombier /*
103e12c5d1SDavid du Colombier  * Plan 9 has two kernel allocators, the x... routines provide a first
113e12c5d1SDavid du Colombier  * fit hole allocator which should be used for permanent or large structures.
123e12c5d1SDavid du Colombier  * Routines are provided to allocate aligned memory which does not cross
133e12c5d1SDavid du Colombier  * arbitrary 2^n boundaries. A second allocator malloc, smalloc, free is
143e12c5d1SDavid du Colombier  * a 2n bucket allocator which steals from the x routines. This should
153e12c5d1SDavid du Colombier  * be used for small frequently used structures.
163e12c5d1SDavid du Colombier  */
173e12c5d1SDavid du Colombier 
183e12c5d1SDavid du Colombier #define	nil		((void*)0)
193e12c5d1SDavid du Colombier #define datoff		((ulong)((Xhdr*)0)->data)
203e12c5d1SDavid du Colombier #define bdatoff		((ulong)((Bucket*)0)->data)
213e12c5d1SDavid du Colombier 
223e12c5d1SDavid du Colombier enum
233e12c5d1SDavid du Colombier {
243e12c5d1SDavid du Colombier 	Maxpow		= 18,
253e12c5d1SDavid du Colombier 	CUTOFF		= 12,
263e12c5d1SDavid du Colombier 	Nhole		= 128,
273e12c5d1SDavid du Colombier 	Magichole	= 0xDeadBabe,
283e12c5d1SDavid du Colombier 	Magic2n		= 0xFeedBeef,
293e12c5d1SDavid du Colombier 	Spanlist	= 64,
30*219b2ee8SDavid du Colombier 
31*219b2ee8SDavid du Colombier 	NTRACE		= 20,
323e12c5d1SDavid du Colombier };
333e12c5d1SDavid du Colombier 
343e12c5d1SDavid du Colombier typedef struct Hole Hole;
353e12c5d1SDavid du Colombier typedef struct Xalloc Xalloc;
363e12c5d1SDavid du Colombier typedef struct Xhdr Xhdr;
373e12c5d1SDavid du Colombier typedef struct Bucket Bucket;
383e12c5d1SDavid du Colombier typedef struct Arena Arena;
393e12c5d1SDavid du Colombier 
403e12c5d1SDavid du Colombier struct Hole
413e12c5d1SDavid du Colombier {
423e12c5d1SDavid du Colombier 	ulong	addr;
433e12c5d1SDavid du Colombier 	ulong	size;
443e12c5d1SDavid du Colombier 	ulong	top;
453e12c5d1SDavid du Colombier 	Hole	*link;
463e12c5d1SDavid du Colombier };
473e12c5d1SDavid du Colombier 
483e12c5d1SDavid du Colombier struct Xhdr
493e12c5d1SDavid du Colombier {
503e12c5d1SDavid du Colombier 	ulong	size;
513e12c5d1SDavid du Colombier 	ulong	magix;
523e12c5d1SDavid du Colombier 	char	data[1];
533e12c5d1SDavid du Colombier };
543e12c5d1SDavid du Colombier 
553e12c5d1SDavid du Colombier struct Xalloc
563e12c5d1SDavid du Colombier {
573e12c5d1SDavid du Colombier 	Lock;
583e12c5d1SDavid du Colombier 	Hole	hole[Nhole];
593e12c5d1SDavid du Colombier 	Hole	*flist;
603e12c5d1SDavid du Colombier 	Hole	*table;
613e12c5d1SDavid du Colombier };
623e12c5d1SDavid du Colombier 
633e12c5d1SDavid du Colombier struct Bucket
643e12c5d1SDavid du Colombier {
653e12c5d1SDavid du Colombier 	int	size;
663e12c5d1SDavid du Colombier 	int	magic;
673e12c5d1SDavid du Colombier 	Bucket	*next;
68*219b2ee8SDavid du Colombier 	ulong	pc;
693e12c5d1SDavid du Colombier 	char	data[1];
703e12c5d1SDavid du Colombier };
713e12c5d1SDavid du Colombier 
723e12c5d1SDavid du Colombier struct Arena
733e12c5d1SDavid du Colombier {
743e12c5d1SDavid du Colombier 	Lock;
753e12c5d1SDavid du Colombier 	Bucket	*btab[Maxpow];
763e12c5d1SDavid du Colombier 	int	nbuck[Maxpow];
77*219b2ee8SDavid du Colombier 	struct{
78*219b2ee8SDavid du Colombier 		ulong	pc;
79*219b2ee8SDavid du Colombier 		ulong	alloc;
80*219b2ee8SDavid du Colombier 		ulong	free;
81*219b2ee8SDavid du Colombier 	}	trace[NTRACE];
823e12c5d1SDavid du Colombier 	QLock	rq;
833e12c5d1SDavid du Colombier 	Rendez	r;
843e12c5d1SDavid du Colombier };
853e12c5d1SDavid du Colombier 
863e12c5d1SDavid du Colombier static Arena	arena;
873e12c5d1SDavid du Colombier static Xalloc	xlists;
883e12c5d1SDavid du Colombier 
893e12c5d1SDavid du Colombier void
903e12c5d1SDavid du Colombier xinit(void)
913e12c5d1SDavid du Colombier {
923e12c5d1SDavid du Colombier 	Hole *h, *eh;
933e12c5d1SDavid du Colombier 	int up, np0, np1;
943e12c5d1SDavid du Colombier 
953e12c5d1SDavid du Colombier 	eh = &xlists.hole[Nhole-1];
963e12c5d1SDavid du Colombier 	for(h = xlists.hole; h < eh; h++)
973e12c5d1SDavid du Colombier 		h->link = h+1;
983e12c5d1SDavid du Colombier 
993e12c5d1SDavid du Colombier 	xlists.flist = xlists.hole;
1003e12c5d1SDavid du Colombier 
1013e12c5d1SDavid du Colombier 	up = conf.upages;
1023e12c5d1SDavid du Colombier 	np1 = up;
1033e12c5d1SDavid du Colombier 	if(np1 > conf.npage1)
1043e12c5d1SDavid du Colombier 		np1 = conf.npage1;
1053e12c5d1SDavid du Colombier 
106*219b2ee8SDavid du Colombier 	palloc.p1 = conf.base1 + (conf.npage1 - np1)*BY2PG;
1073e12c5d1SDavid du Colombier 	conf.npage1 -= np1;
1083e12c5d1SDavid du Colombier 	xhole(conf.base1, conf.npage1*BY2PG);
1093e12c5d1SDavid du Colombier 	conf.npage1 = conf.base1+(conf.npage1*BY2PG);
1103e12c5d1SDavid du Colombier 	up -= np1;
1113e12c5d1SDavid du Colombier 
1123e12c5d1SDavid du Colombier 	np0 = up;
1133e12c5d1SDavid du Colombier 	if(np0 > conf.npage0)
1143e12c5d1SDavid du Colombier 		np0 = conf.npage0;
1153e12c5d1SDavid du Colombier 
116*219b2ee8SDavid du Colombier 	palloc.p0 = conf.base0 + (conf.npage0 - np0)*BY2PG;
1173e12c5d1SDavid du Colombier 	conf.npage0 -= np0;
1183e12c5d1SDavid du Colombier 	xhole(conf.base0, conf.npage0*BY2PG);
1193e12c5d1SDavid du Colombier 	conf.npage0 = conf.base0+(conf.npage0*BY2PG);
1203e12c5d1SDavid du Colombier 
1213e12c5d1SDavid du Colombier 	palloc.np0 = np0;
1223e12c5d1SDavid du Colombier 	palloc.np1 = np1;
1233e12c5d1SDavid du Colombier 	/* Save the bounds of kernel alloc memory for kernel mmu mapping */
1243e12c5d1SDavid du Colombier 	conf.base0 = (ulong)KADDR(conf.base0);
1253e12c5d1SDavid du Colombier 	conf.base1 = (ulong)KADDR(conf.base1);
1263e12c5d1SDavid du Colombier 	conf.npage0 = (ulong)KADDR(conf.npage0);
1273e12c5d1SDavid du Colombier 	conf.npage1 = (ulong)KADDR(conf.npage1);
1283e12c5d1SDavid du Colombier }
1293e12c5d1SDavid du Colombier 
1303e12c5d1SDavid du Colombier /*
1313e12c5d1SDavid du Colombier  * NB. spanalloc memory will cause a panic if free'd
1323e12c5d1SDavid du Colombier  */
1333e12c5d1SDavid du Colombier void*
1343e12c5d1SDavid du Colombier xspanalloc(ulong size, int align, ulong span)
1353e12c5d1SDavid du Colombier {
1363e12c5d1SDavid du Colombier 	int i, j;
1373e12c5d1SDavid du Colombier 	ulong a, p, sinc;
1383e12c5d1SDavid du Colombier 	ulong ptr[Spanlist];
1393e12c5d1SDavid du Colombier 
1403e12c5d1SDavid du Colombier 	sinc = size/8;
1413e12c5d1SDavid du Colombier 	span = ~(span-1);
1423e12c5d1SDavid du Colombier 	for(i = 0; i < Spanlist; i++) {
1433e12c5d1SDavid du Colombier 		p = (ulong)xalloc(size+align);
1443e12c5d1SDavid du Colombier 		if(p == 0)
1453e12c5d1SDavid du Colombier 			break;
1463e12c5d1SDavid du Colombier 
1473e12c5d1SDavid du Colombier 		a = p+align;
1483e12c5d1SDavid du Colombier 		a &= ~(align-1);
1493e12c5d1SDavid du Colombier 		if((a&span) == ((a+size)&span)) {
1503e12c5d1SDavid du Colombier 			for(j = 0; j < i; j++)
1513e12c5d1SDavid du Colombier 				if(ptr[j])
1523e12c5d1SDavid du Colombier 					xfree((void*)ptr[j]);
1533e12c5d1SDavid du Colombier 
1543e12c5d1SDavid du Colombier 			return (void*)a;
1553e12c5d1SDavid du Colombier 		}
1563e12c5d1SDavid du Colombier 		xfree((void*)p);
1573e12c5d1SDavid du Colombier 		ptr[i] = (ulong)xalloc(sinc);
1583e12c5d1SDavid du Colombier 	}
1593e12c5d1SDavid du Colombier 	USED(sinc);
1603e12c5d1SDavid du Colombier 	xsummary();
1613e12c5d1SDavid du Colombier 	panic("xspanalloc: %d %d %lux\n", size, align, span);
1623e12c5d1SDavid du Colombier 	return 0;
1633e12c5d1SDavid du Colombier }
1643e12c5d1SDavid du Colombier 
1653e12c5d1SDavid du Colombier void*
1663e12c5d1SDavid du Colombier xalloc(ulong size)
1673e12c5d1SDavid du Colombier {
1683e12c5d1SDavid du Colombier 	Xhdr *p;
1693e12c5d1SDavid du Colombier 	Hole *h, **l;
1703e12c5d1SDavid du Colombier 
1713e12c5d1SDavid du Colombier 	size += BY2WD + sizeof(Xhdr);
1723e12c5d1SDavid du Colombier 	size &= ~(BY2WD-1);
1733e12c5d1SDavid du Colombier 
1743e12c5d1SDavid du Colombier 	lock(&xlists);
1753e12c5d1SDavid du Colombier 	l = &xlists.table;
1763e12c5d1SDavid du Colombier 	for(h = *l; h; h = h->link) {
1773e12c5d1SDavid du Colombier 		if(h->size >= size) {
1783e12c5d1SDavid du Colombier 			p = (Xhdr*)h->addr;
1793e12c5d1SDavid du Colombier 			h->addr += size;
1803e12c5d1SDavid du Colombier 			h->size -= size;
1813e12c5d1SDavid du Colombier 			if(h->size == 0) {
1823e12c5d1SDavid du Colombier 				*l = h->link;
1833e12c5d1SDavid du Colombier 				h->link = xlists.flist;
1843e12c5d1SDavid du Colombier 				xlists.flist = h;
1853e12c5d1SDavid du Colombier 			}
1863e12c5d1SDavid du Colombier 			unlock(&xlists);
1873e12c5d1SDavid du Colombier 			p = KADDR(p);
1883e12c5d1SDavid du Colombier 			memset(p, 0, size);
1893e12c5d1SDavid du Colombier 			p->magix = Magichole;
1903e12c5d1SDavid du Colombier 			p->size = size;
1913e12c5d1SDavid du Colombier 			return p->data;
1923e12c5d1SDavid du Colombier 		}
1933e12c5d1SDavid du Colombier 		l = &h->link;
1943e12c5d1SDavid du Colombier 	}
1953e12c5d1SDavid du Colombier 	unlock(&xlists);
1963e12c5d1SDavid du Colombier 	return nil;
1973e12c5d1SDavid du Colombier }
1983e12c5d1SDavid du Colombier 
1993e12c5d1SDavid du Colombier void
2003e12c5d1SDavid du Colombier xfree(void *p)
2013e12c5d1SDavid du Colombier {
2023e12c5d1SDavid du Colombier 	Xhdr *x;
2033e12c5d1SDavid du Colombier 
2043e12c5d1SDavid du Colombier 	x = (Xhdr*)((ulong)p - datoff);
2053e12c5d1SDavid du Colombier 	if(x->magix != Magichole)
2063e12c5d1SDavid du Colombier 		panic("xfree");
2073e12c5d1SDavid du Colombier 
2083e12c5d1SDavid du Colombier 	xhole(PADDR(x), x->size);
2093e12c5d1SDavid du Colombier }
2103e12c5d1SDavid du Colombier 
2113e12c5d1SDavid du Colombier void
2123e12c5d1SDavid du Colombier xhole(ulong addr, ulong size)
2133e12c5d1SDavid du Colombier {
2143e12c5d1SDavid du Colombier 	ulong top;
2153e12c5d1SDavid du Colombier 	Hole *h, *c, **l;
2163e12c5d1SDavid du Colombier 
2173e12c5d1SDavid du Colombier 	if(size == 0)
2183e12c5d1SDavid du Colombier 		return;
2193e12c5d1SDavid du Colombier 
2203e12c5d1SDavid du Colombier 	top = addr + size;
2213e12c5d1SDavid du Colombier 	lock(&xlists);
2223e12c5d1SDavid du Colombier 	l = &xlists.table;
2233e12c5d1SDavid du Colombier 	for(h = *l; h; h = h->link) {
2243e12c5d1SDavid du Colombier 		if(h->top == addr) {
2253e12c5d1SDavid du Colombier 			h->size += size;
2263e12c5d1SDavid du Colombier 			h->top = h->addr+h->size;
2273e12c5d1SDavid du Colombier 			c = h->link;
2283e12c5d1SDavid du Colombier 			if(c && h->top == c->addr) {
2293e12c5d1SDavid du Colombier 				h->top += c->size;
2303e12c5d1SDavid du Colombier 				h->size += c->size;
2313e12c5d1SDavid du Colombier 				h->link = c->link;
2323e12c5d1SDavid du Colombier 				c->link = xlists.flist;
2333e12c5d1SDavid du Colombier 				xlists.flist = c;
2343e12c5d1SDavid du Colombier 			}
2353e12c5d1SDavid du Colombier 			unlock(&xlists);
2363e12c5d1SDavid du Colombier 			return;
2373e12c5d1SDavid du Colombier 		}
2383e12c5d1SDavid du Colombier 		if(h->addr > addr)
2393e12c5d1SDavid du Colombier 			break;
2403e12c5d1SDavid du Colombier 		l = &h->link;
2413e12c5d1SDavid du Colombier 	}
2423e12c5d1SDavid du Colombier 	if(h && top == h->addr) {
2433e12c5d1SDavid du Colombier 		h->addr -= size;
2443e12c5d1SDavid du Colombier 		h->size += size;
2453e12c5d1SDavid du Colombier 		unlock(&xlists);
2463e12c5d1SDavid du Colombier 		return;
2473e12c5d1SDavid du Colombier 	}
2483e12c5d1SDavid du Colombier 
2493e12c5d1SDavid du Colombier 	if(xlists.flist == nil) {
2503e12c5d1SDavid du Colombier 		unlock(&xlists);
2513e12c5d1SDavid du Colombier 		print("xfree: no free holes, leaked %d bytes\n", size);
2523e12c5d1SDavid du Colombier 		return;
2533e12c5d1SDavid du Colombier 	}
2543e12c5d1SDavid du Colombier 
2553e12c5d1SDavid du Colombier 	h = xlists.flist;
2563e12c5d1SDavid du Colombier 	xlists.flist = h->link;
2573e12c5d1SDavid du Colombier 	h->addr = addr;
2583e12c5d1SDavid du Colombier 	h->top = top;
2593e12c5d1SDavid du Colombier 	h->size = size;
2603e12c5d1SDavid du Colombier 	h->link = *l;
2613e12c5d1SDavid du Colombier 	*l = h;
2623e12c5d1SDavid du Colombier 	unlock(&xlists);
2633e12c5d1SDavid du Colombier }
2643e12c5d1SDavid du Colombier 
265*219b2ee8SDavid du Colombier void
266*219b2ee8SDavid du Colombier alloctrace(void *p, ulong pc)
267*219b2ee8SDavid du Colombier {
268*219b2ee8SDavid du Colombier 	Bucket *bp;
269*219b2ee8SDavid du Colombier 	int i;
270*219b2ee8SDavid du Colombier 
271*219b2ee8SDavid du Colombier 	bp = (Bucket*)((ulong)p - bdatoff);
272*219b2ee8SDavid du Colombier 	if(bp->size != 13)
273*219b2ee8SDavid du Colombier 		return;
274*219b2ee8SDavid du Colombier 	bp->pc = pc;
275*219b2ee8SDavid du Colombier 	lock(&arena);
276*219b2ee8SDavid du Colombier 	for(i = 0; i < NTRACE; i++){
277*219b2ee8SDavid du Colombier 		if(arena.trace[i].pc == 0)
278*219b2ee8SDavid du Colombier 			arena.trace[i].pc = pc;
279*219b2ee8SDavid du Colombier 		if(arena.trace[i].pc == pc){
280*219b2ee8SDavid du Colombier 			arena.trace[i].alloc++;
281*219b2ee8SDavid du Colombier 			break;
282*219b2ee8SDavid du Colombier 		}
283*219b2ee8SDavid du Colombier 	}
284*219b2ee8SDavid du Colombier 	unlock(&arena);
285*219b2ee8SDavid du Colombier }
286*219b2ee8SDavid du Colombier 
2873e12c5d1SDavid du Colombier void*
2883e12c5d1SDavid du Colombier malloc(ulong size)
2893e12c5d1SDavid du Colombier {
2903e12c5d1SDavid du Colombier 	ulong next;
2913e12c5d1SDavid du Colombier 	int pow, n;
2923e12c5d1SDavid du Colombier 	Bucket *bp, *nbp;
2933e12c5d1SDavid du Colombier 
294*219b2ee8SDavid du Colombier 	for(pow = 3; pow < Maxpow; pow++)
2953e12c5d1SDavid du Colombier 		if(size <= (1<<pow))
2963e12c5d1SDavid du Colombier 			goto good;
2973e12c5d1SDavid du Colombier 
2983e12c5d1SDavid du Colombier 	return nil;
2993e12c5d1SDavid du Colombier good:
3003e12c5d1SDavid du Colombier 	/* Allocate off this list */
3013e12c5d1SDavid du Colombier 	lock(&arena);
3023e12c5d1SDavid du Colombier 	bp = arena.btab[pow];
3033e12c5d1SDavid du Colombier 	if(bp) {
3043e12c5d1SDavid du Colombier 		arena.btab[pow] = bp->next;
305*219b2ee8SDavid du Colombier 		if(bp->magic != 0 || bp->size != pow){
306*219b2ee8SDavid du Colombier 			unlock(&arena);
307*219b2ee8SDavid du Colombier 			panic("malloc bp %lux magic %lux size %d next %lux pow %d", bp,
308*219b2ee8SDavid du Colombier 				bp->magic, bp->size, bp->next, pow);
309*219b2ee8SDavid du Colombier 		}
310*219b2ee8SDavid du Colombier 		bp->magic = Magic2n;
3113e12c5d1SDavid du Colombier 		unlock(&arena);
3123e12c5d1SDavid du Colombier 
3133e12c5d1SDavid du Colombier 		memset(bp->data, 0, size);
314*219b2ee8SDavid du Colombier 		bp->pc = getcallerpc(((uchar*)&size) - sizeof(size));
3153e12c5d1SDavid du Colombier 		return  bp->data;
3163e12c5d1SDavid du Colombier 	}
3173e12c5d1SDavid du Colombier 	unlock(&arena);
3183e12c5d1SDavid du Colombier 
3193e12c5d1SDavid du Colombier 	size = sizeof(Bucket)+(1<<pow);
3203e12c5d1SDavid du Colombier 	size += 3;
3213e12c5d1SDavid du Colombier 	size &= ~3;
3223e12c5d1SDavid du Colombier 
3233e12c5d1SDavid du Colombier 	if(pow < CUTOFF) {
3243e12c5d1SDavid du Colombier 		n = (CUTOFF-pow)+2;
3253e12c5d1SDavid du Colombier 		bp = xalloc(size*n);
3263e12c5d1SDavid du Colombier 		if(bp == nil)
3273e12c5d1SDavid du Colombier 			return nil;
3283e12c5d1SDavid du Colombier 
329*219b2ee8SDavid du Colombier 		nbp = bp;
3303e12c5d1SDavid du Colombier 		lock(&arena);
3313e12c5d1SDavid du Colombier 		arena.nbuck[pow] += n;
332*219b2ee8SDavid du Colombier 		while(--n) {
3333e12c5d1SDavid du Colombier 			next = (ulong)nbp+size;
334*219b2ee8SDavid du Colombier 			nbp = (Bucket*)next;
3353e12c5d1SDavid du Colombier 			nbp->size = pow;
336*219b2ee8SDavid du Colombier 			nbp->next = arena.btab[pow];
337*219b2ee8SDavid du Colombier 			arena.btab[pow] = nbp;
3383e12c5d1SDavid du Colombier 		}
3393e12c5d1SDavid du Colombier 		unlock(&arena);
3403e12c5d1SDavid du Colombier 	}
3413e12c5d1SDavid du Colombier 	else {
3423e12c5d1SDavid du Colombier 		bp = xalloc(size);
3433e12c5d1SDavid du Colombier 		if(bp == nil)
3443e12c5d1SDavid du Colombier 			return nil;
3453e12c5d1SDavid du Colombier 
3463e12c5d1SDavid du Colombier 		arena.nbuck[pow]++;
3473e12c5d1SDavid du Colombier 	}
3483e12c5d1SDavid du Colombier 
3493e12c5d1SDavid du Colombier 	bp->size = pow;
3503e12c5d1SDavid du Colombier 	bp->magic = Magic2n;
351*219b2ee8SDavid du Colombier 	bp->pc = getcallerpc(((uchar*)&size) - sizeof(size));
3523e12c5d1SDavid du Colombier 	return bp->data;
3533e12c5d1SDavid du Colombier }
3543e12c5d1SDavid du Colombier 
3553e12c5d1SDavid du Colombier void*
3563e12c5d1SDavid du Colombier smalloc(ulong size)
3573e12c5d1SDavid du Colombier {
3583e12c5d1SDavid du Colombier 	char *s;
3593e12c5d1SDavid du Colombier 	void *p;
3603e12c5d1SDavid du Colombier 	int attempt;
361*219b2ee8SDavid du Colombier 	Bucket *bp;
3623e12c5d1SDavid du Colombier 
3633e12c5d1SDavid du Colombier 	for(attempt = 0; attempt < 1000; attempt++) {
3643e12c5d1SDavid du Colombier 		p = malloc(size);
365*219b2ee8SDavid du Colombier 		if(p != nil) {
366*219b2ee8SDavid du Colombier 			bp = (Bucket*)((ulong)p - bdatoff);
367*219b2ee8SDavid du Colombier 			bp->pc = getcallerpc(((uchar*)&size) - sizeof(size));
3683e12c5d1SDavid du Colombier 			return p;
369*219b2ee8SDavid du Colombier 		}
3703e12c5d1SDavid du Colombier 		s = u->p->psstate;
3713e12c5d1SDavid du Colombier 		u->p->psstate = "Malloc";
3723e12c5d1SDavid du Colombier 		qlock(&arena.rq);
3733e12c5d1SDavid du Colombier 		while(waserror())
3743e12c5d1SDavid du Colombier 			;
3753e12c5d1SDavid du Colombier 		sleep(&arena.r, return0, nil);
3763e12c5d1SDavid du Colombier 		poperror();
3773e12c5d1SDavid du Colombier 		qunlock(&arena.rq);
3783e12c5d1SDavid du Colombier 		u->p->psstate = s;
3793e12c5d1SDavid du Colombier 	}
380*219b2ee8SDavid du Colombier 	print("%s:%d: out of memory in smalloc %d\n", u->p->text, u->p->pid, size);
381*219b2ee8SDavid du Colombier 	u->p->state = Broken;
382*219b2ee8SDavid du Colombier 	u->p->psstate = "NoMem";
383*219b2ee8SDavid du Colombier 	for(;;)
384*219b2ee8SDavid du Colombier 		sched();
3853e12c5d1SDavid du Colombier 	return 0;
3863e12c5d1SDavid du Colombier }
3873e12c5d1SDavid du Colombier 
3883e12c5d1SDavid du Colombier int
3893e12c5d1SDavid du Colombier msize(void *ptr)
3903e12c5d1SDavid du Colombier {
3913e12c5d1SDavid du Colombier 	Bucket *bp;
3923e12c5d1SDavid du Colombier 
3933e12c5d1SDavid du Colombier 	bp = (Bucket*)((ulong)ptr - bdatoff);
3943e12c5d1SDavid du Colombier 	if(bp->magic != Magic2n)
3953e12c5d1SDavid du Colombier 		panic("msize");
3963e12c5d1SDavid du Colombier 	return 1<<bp->size;
3973e12c5d1SDavid du Colombier }
3983e12c5d1SDavid du Colombier 
3993e12c5d1SDavid du Colombier void
4003e12c5d1SDavid du Colombier free(void *ptr)
4013e12c5d1SDavid du Colombier {
402*219b2ee8SDavid du Colombier 	ulong pc, n;
4033e12c5d1SDavid du Colombier 	Bucket *bp, **l;
4043e12c5d1SDavid du Colombier 
4053e12c5d1SDavid du Colombier 	bp = (Bucket*)((ulong)ptr - bdatoff);
406*219b2ee8SDavid du Colombier 	l = &arena.btab[bp->size];
407*219b2ee8SDavid du Colombier 
408*219b2ee8SDavid du Colombier 	lock(&arena);
4093e12c5d1SDavid du Colombier 	if(bp->magic != Magic2n)
4103e12c5d1SDavid du Colombier 		panic("free");
4113e12c5d1SDavid du Colombier 	bp->magic = 0;
4123e12c5d1SDavid du Colombier 	bp->next = *l;
4133e12c5d1SDavid du Colombier 	*l = bp;
414*219b2ee8SDavid du Colombier 	if(bp->size == 13) {
415*219b2ee8SDavid du Colombier 		pc = bp->pc;
416*219b2ee8SDavid du Colombier 		for(n = 0; n < NTRACE; n++){
417*219b2ee8SDavid du Colombier 			if(arena.trace[n].pc == pc){
418*219b2ee8SDavid du Colombier 				arena.trace[n].free++;
419*219b2ee8SDavid du Colombier 				break;
420*219b2ee8SDavid du Colombier 			}
421*219b2ee8SDavid du Colombier 		}
422*219b2ee8SDavid du Colombier 	}
4233e12c5d1SDavid du Colombier 	unlock(&arena);
4243e12c5d1SDavid du Colombier 	if(arena.r.p)
4253e12c5d1SDavid du Colombier 		wakeup(&arena.r);
4263e12c5d1SDavid du Colombier }
4273e12c5d1SDavid du Colombier 
4283e12c5d1SDavid du Colombier void
4293e12c5d1SDavid du Colombier xsummary(void)
4303e12c5d1SDavid du Colombier {
4313e12c5d1SDavid du Colombier 	Hole *h;
4323e12c5d1SDavid du Colombier 	Bucket *k;
4333e12c5d1SDavid du Colombier 	int i, nfree, nused;
4343e12c5d1SDavid du Colombier 
4353e12c5d1SDavid du Colombier 	i = 0;
4363e12c5d1SDavid du Colombier 	for(h = xlists.flist; h; h = h->link)
4373e12c5d1SDavid du Colombier 		i++;
4383e12c5d1SDavid du Colombier 
4393e12c5d1SDavid du Colombier 	print("%d holes free\n", i);
4403e12c5d1SDavid du Colombier 	i = 0;
4413e12c5d1SDavid du Colombier 	for(h = xlists.table; h; h = h->link) {
4423e12c5d1SDavid du Colombier 		print("%.8lux %.8lux %d\n", h->addr, h->top, h->size);
4433e12c5d1SDavid du Colombier 		i += h->size;
4443e12c5d1SDavid du Colombier 	}
4453e12c5d1SDavid du Colombier 	print("%d bytes free\n", i);
4463e12c5d1SDavid du Colombier 	nused = 0;
4473e12c5d1SDavid du Colombier 	for(i = 3; i < Maxpow; i++) {
4483e12c5d1SDavid du Colombier 		if(arena.btab[i] == 0 && arena.nbuck[i] == 0)
4493e12c5d1SDavid du Colombier 			continue;
4503e12c5d1SDavid du Colombier 		nused += arena.nbuck[i]*(1<<i);
4513e12c5d1SDavid du Colombier 		nfree = 0;
4523e12c5d1SDavid du Colombier 		for(k = arena.btab[i]; k; k = k->next)
4533e12c5d1SDavid du Colombier 			nfree++;
4543e12c5d1SDavid du Colombier 		print("%8d %4d %4d\n", 1<<i, arena.nbuck[i], nfree);
4553e12c5d1SDavid du Colombier 	}
456*219b2ee8SDavid du Colombier 	for(i = 0; i < NTRACE && arena.trace[i].pc; i++)
457*219b2ee8SDavid du Colombier 		print("%lux %d %d\n", arena.trace[i].pc, arena.trace[i].alloc, arena.trace[i].free);
4583e12c5d1SDavid du Colombier 	print("%d bytes in pool\n", nused);
4593e12c5d1SDavid du Colombier }
460