xref: /inferno-os/emu/port/alloc.c (revision 7828d5d2aa2aeba1588dba190fd80dcab95d982b)
137da2899SCharles.Forsyth #include "dat.h"
237da2899SCharles.Forsyth #include "fns.h"
337da2899SCharles.Forsyth #include "interp.h"
437da2899SCharles.Forsyth #include "error.h"
537da2899SCharles.Forsyth 
637da2899SCharles.Forsyth enum
737da2899SCharles.Forsyth {
837da2899SCharles.Forsyth 	MAXPOOL		= 4
937da2899SCharles.Forsyth };
1037da2899SCharles.Forsyth 
1137da2899SCharles.Forsyth #define left	u.s.bhl
1237da2899SCharles.Forsyth #define right	u.s.bhr
1337da2899SCharles.Forsyth #define fwd	u.s.bhf
1437da2899SCharles.Forsyth #define prev	u.s.bhv
1537da2899SCharles.Forsyth #define parent	u.s.bhp
1637da2899SCharles.Forsyth 
1737da2899SCharles.Forsyth #define RESERVED	512*1024
1837da2899SCharles.Forsyth 
1937da2899SCharles.Forsyth struct Pool
2037da2899SCharles.Forsyth {
2137da2899SCharles.Forsyth 	char*	name;
2237da2899SCharles.Forsyth 	int	pnum;
2337da2899SCharles.Forsyth 	ulong	maxsize;
2437da2899SCharles.Forsyth 	int	quanta;
2537da2899SCharles.Forsyth 	int	chunk;
2637da2899SCharles.Forsyth 	int	monitor;
2737da2899SCharles.Forsyth 	ulong	ressize;	/* restricted size */
2837da2899SCharles.Forsyth 	ulong	cursize;
2937da2899SCharles.Forsyth 	ulong	arenasize;
3037da2899SCharles.Forsyth 	ulong	hw;
3137da2899SCharles.Forsyth 	Lock	l;
3237da2899SCharles.Forsyth 	Bhdr*	root;
3337da2899SCharles.Forsyth 	Bhdr*	chain;
3437da2899SCharles.Forsyth 	ulong	nalloc;
3537da2899SCharles.Forsyth 	ulong	nfree;
3637da2899SCharles.Forsyth 	int	nbrk;
3737da2899SCharles.Forsyth 	int	lastfree;
3837da2899SCharles.Forsyth 	void	(*move)(void*, void*);
3937da2899SCharles.Forsyth };
4037da2899SCharles.Forsyth 
4137da2899SCharles.Forsyth void*	initbrk(ulong);
4237da2899SCharles.Forsyth 
4337da2899SCharles.Forsyth struct
4437da2899SCharles.Forsyth {
4537da2899SCharles.Forsyth 	int	n;
4637da2899SCharles.Forsyth 	Pool	pool[MAXPOOL];
4737da2899SCharles.Forsyth 	/* Lock l; */
4837da2899SCharles.Forsyth } table = {
4937da2899SCharles.Forsyth 	3,
5037da2899SCharles.Forsyth 	{
5137da2899SCharles.Forsyth 		{ "main",  0, 	32*1024*1024, 31,  512*1024, 0, 31*1024*1024 },
5237da2899SCharles.Forsyth 		{ "heap",  1, 	32*1024*1024, 31,  512*1024, 0, 31*1024*1024 },
53e55a4b3eSYaroslav Kolomiiets 		{ "image", 2,   64*1024*1024+256, 31, 4*1024*1024, 1, 63*1024*1024 },
5437da2899SCharles.Forsyth 	}
5537da2899SCharles.Forsyth };
5637da2899SCharles.Forsyth 
5737da2899SCharles.Forsyth Pool*	mainmem = &table.pool[0];
5837da2899SCharles.Forsyth Pool*	heapmem = &table.pool[1];
5937da2899SCharles.Forsyth Pool*	imagmem = &table.pool[2];
6037da2899SCharles.Forsyth 
6137da2899SCharles.Forsyth static void _auditmemloc(char *, void *);
6237da2899SCharles.Forsyth void (*auditmemloc)(char *, void *) = _auditmemloc;
6337da2899SCharles.Forsyth static void _poolfault(void *, char *, ulong);
6437da2899SCharles.Forsyth void (*poolfault)(void *, char *, ulong) = _poolfault;
6537da2899SCharles.Forsyth 
6637da2899SCharles.Forsyth /*	non tracing
6737da2899SCharles.Forsyth  *
6837da2899SCharles.Forsyth enum {
6937da2899SCharles.Forsyth 	Npadlong	= 0,
7037da2899SCharles.Forsyth 	MallocOffset = 0,
7137da2899SCharles.Forsyth 	ReallocOffset = 0
7237da2899SCharles.Forsyth };
7337da2899SCharles.Forsyth  *
7437da2899SCharles.Forsyth  */
7537da2899SCharles.Forsyth 
7637da2899SCharles.Forsyth /* tracing */
7737da2899SCharles.Forsyth enum {
7837da2899SCharles.Forsyth 	Npadlong	= 2,
7937da2899SCharles.Forsyth 	MallocOffset = 0,
8037da2899SCharles.Forsyth 	ReallocOffset = 1
8137da2899SCharles.Forsyth };
8237da2899SCharles.Forsyth 
8337da2899SCharles.Forsyth enum {
8437da2899SCharles.Forsyth 	Monitor = 1
8537da2899SCharles.Forsyth };
8637da2899SCharles.Forsyth 
8737da2899SCharles.Forsyth void	(*memmonitor)(int, ulong, ulong, ulong) = nil;
8837da2899SCharles.Forsyth #define	MM(v,pc,base,size)	if(!Monitor || memmonitor==nil){} else memmonitor((v),(pc),(base),(size))
8937da2899SCharles.Forsyth 
9037da2899SCharles.Forsyth #define CKLEAK	0
9137da2899SCharles.Forsyth int	ckleak;
9237da2899SCharles.Forsyth #define	ML(v, sz, pc)	if(CKLEAK && ckleak && v){ if(sz) fprint(2, "%lux %lux %lux\n", (ulong)v, (ulong)sz, (ulong)pc); else fprint(2, "%lux\n", (ulong)v); }
9337da2899SCharles.Forsyth 
9437da2899SCharles.Forsyth int
memusehigh(void)9537da2899SCharles.Forsyth memusehigh(void)
9637da2899SCharles.Forsyth {
9737da2899SCharles.Forsyth 	return 	mainmem->cursize > mainmem->ressize ||
9837da2899SCharles.Forsyth 			heapmem->cursize > heapmem->ressize ||
9937da2899SCharles.Forsyth 			0 && imagmem->cursize > imagmem->ressize;
10037da2899SCharles.Forsyth }
10137da2899SCharles.Forsyth 
10237da2899SCharles.Forsyth int
memlow(void)10337da2899SCharles.Forsyth memlow(void)
10437da2899SCharles.Forsyth {
10537da2899SCharles.Forsyth 	return heapmem->cursize > (heapmem->maxsize)/2;
10637da2899SCharles.Forsyth }
10737da2899SCharles.Forsyth 
10837da2899SCharles.Forsyth int
poolsetsize(char * s,int size)10937da2899SCharles.Forsyth poolsetsize(char *s, int size)
11037da2899SCharles.Forsyth {
11137da2899SCharles.Forsyth 	int i;
11237da2899SCharles.Forsyth 
11337da2899SCharles.Forsyth 	for(i = 0; i < table.n; i++) {
11437da2899SCharles.Forsyth 		if(strcmp(table.pool[i].name, s) == 0) {
11537da2899SCharles.Forsyth 			table.pool[i].maxsize = size;
11637da2899SCharles.Forsyth 			table.pool[i].ressize = size-RESERVED;
11737da2899SCharles.Forsyth 			if(size < RESERVED)
11837da2899SCharles.Forsyth 				panic("not enough memory");
11937da2899SCharles.Forsyth 			return 1;
12037da2899SCharles.Forsyth 		}
12137da2899SCharles.Forsyth 	}
12237da2899SCharles.Forsyth 	return 0;
12337da2899SCharles.Forsyth }
12437da2899SCharles.Forsyth 
12537da2899SCharles.Forsyth void
poolimmutable(void * v)12637da2899SCharles.Forsyth poolimmutable(void *v)
12737da2899SCharles.Forsyth {
12837da2899SCharles.Forsyth 	Bhdr *b;
12937da2899SCharles.Forsyth 
13037da2899SCharles.Forsyth 	D2B(b, v);
13137da2899SCharles.Forsyth 	b->magic = MAGIC_I;
13237da2899SCharles.Forsyth }
13337da2899SCharles.Forsyth 
13437da2899SCharles.Forsyth void
poolmutable(void * v)13537da2899SCharles.Forsyth poolmutable(void *v)
13637da2899SCharles.Forsyth {
13737da2899SCharles.Forsyth 	Bhdr *b;
13837da2899SCharles.Forsyth 
13937da2899SCharles.Forsyth 	D2B(b, v);
14037da2899SCharles.Forsyth 	b->magic = MAGIC_A;
14137da2899SCharles.Forsyth 	((Heap*)v)->color = mutator;
14237da2899SCharles.Forsyth }
14337da2899SCharles.Forsyth 
14437da2899SCharles.Forsyth char*
poolname(Pool * p)14537da2899SCharles.Forsyth poolname(Pool *p)
14637da2899SCharles.Forsyth {
14737da2899SCharles.Forsyth 	return p->name;
14837da2899SCharles.Forsyth }
14937da2899SCharles.Forsyth 
15037da2899SCharles.Forsyth Bhdr*
poolchain(Pool * p)15137da2899SCharles.Forsyth poolchain(Pool *p)
15237da2899SCharles.Forsyth {
15337da2899SCharles.Forsyth 	return p->chain;
15437da2899SCharles.Forsyth }
15537da2899SCharles.Forsyth 
15637da2899SCharles.Forsyth void
pooldel(Pool * p,Bhdr * t)15737da2899SCharles.Forsyth pooldel(Pool *p, Bhdr *t)
15837da2899SCharles.Forsyth {
15937da2899SCharles.Forsyth 	Bhdr *s, *f, *rp, *q;
16037da2899SCharles.Forsyth 
16137da2899SCharles.Forsyth 	if(t->parent == nil && p->root != t) {
16237da2899SCharles.Forsyth 		t->prev->fwd = t->fwd;
16337da2899SCharles.Forsyth 		t->fwd->prev = t->prev;
16437da2899SCharles.Forsyth 		return;
16537da2899SCharles.Forsyth 	}
16637da2899SCharles.Forsyth 
16737da2899SCharles.Forsyth 	if(t->fwd != t) {
16837da2899SCharles.Forsyth 		f = t->fwd;
16937da2899SCharles.Forsyth 		s = t->parent;
17037da2899SCharles.Forsyth 		f->parent = s;
17137da2899SCharles.Forsyth 		if(s == nil)
17237da2899SCharles.Forsyth 			p->root = f;
17337da2899SCharles.Forsyth 		else {
17437da2899SCharles.Forsyth 			if(s->left == t)
17537da2899SCharles.Forsyth 				s->left = f;
17637da2899SCharles.Forsyth 			else
17737da2899SCharles.Forsyth 				s->right = f;
17837da2899SCharles.Forsyth 		}
17937da2899SCharles.Forsyth 
18037da2899SCharles.Forsyth 		rp = t->left;
18137da2899SCharles.Forsyth 		f->left = rp;
18237da2899SCharles.Forsyth 		if(rp != nil)
18337da2899SCharles.Forsyth 			rp->parent = f;
18437da2899SCharles.Forsyth 		rp = t->right;
18537da2899SCharles.Forsyth 		f->right = rp;
18637da2899SCharles.Forsyth 		if(rp != nil)
18737da2899SCharles.Forsyth 			rp->parent = f;
18837da2899SCharles.Forsyth 
18937da2899SCharles.Forsyth 		t->prev->fwd = t->fwd;
19037da2899SCharles.Forsyth 		t->fwd->prev = t->prev;
19137da2899SCharles.Forsyth 		return;
19237da2899SCharles.Forsyth 	}
19337da2899SCharles.Forsyth 
19437da2899SCharles.Forsyth 	if(t->left == nil)
19537da2899SCharles.Forsyth 		rp = t->right;
19637da2899SCharles.Forsyth 	else {
19737da2899SCharles.Forsyth 		if(t->right == nil)
19837da2899SCharles.Forsyth 			rp = t->left;
19937da2899SCharles.Forsyth 		else {
20037da2899SCharles.Forsyth 			f = t;
20137da2899SCharles.Forsyth 			rp = t->right;
20237da2899SCharles.Forsyth 			s = rp->left;
20337da2899SCharles.Forsyth 			while(s != nil) {
20437da2899SCharles.Forsyth 				f = rp;
20537da2899SCharles.Forsyth 				rp = s;
20637da2899SCharles.Forsyth 				s = rp->left;
20737da2899SCharles.Forsyth 			}
20837da2899SCharles.Forsyth 			if(f != t) {
20937da2899SCharles.Forsyth 				s = rp->right;
21037da2899SCharles.Forsyth 				f->left = s;
21137da2899SCharles.Forsyth 				if(s != nil)
21237da2899SCharles.Forsyth 					s->parent = f;
21337da2899SCharles.Forsyth 				s = t->right;
21437da2899SCharles.Forsyth 				rp->right = s;
21537da2899SCharles.Forsyth 				if(s != nil)
21637da2899SCharles.Forsyth 					s->parent = rp;
21737da2899SCharles.Forsyth 			}
21837da2899SCharles.Forsyth 			s = t->left;
21937da2899SCharles.Forsyth 			rp->left = s;
22037da2899SCharles.Forsyth 			s->parent = rp;
22137da2899SCharles.Forsyth 		}
22237da2899SCharles.Forsyth 	}
22337da2899SCharles.Forsyth 	q = t->parent;
22437da2899SCharles.Forsyth 	if(q == nil)
22537da2899SCharles.Forsyth 		p->root = rp;
22637da2899SCharles.Forsyth 	else {
22737da2899SCharles.Forsyth 		if(t == q->left)
22837da2899SCharles.Forsyth 			q->left = rp;
22937da2899SCharles.Forsyth 		else
23037da2899SCharles.Forsyth 			q->right = rp;
23137da2899SCharles.Forsyth 	}
23237da2899SCharles.Forsyth 	if(rp != nil)
23337da2899SCharles.Forsyth 		rp->parent = q;
23437da2899SCharles.Forsyth }
23537da2899SCharles.Forsyth 
23637da2899SCharles.Forsyth void
pooladd(Pool * p,Bhdr * q)23737da2899SCharles.Forsyth pooladd(Pool *p, Bhdr *q)
23837da2899SCharles.Forsyth {
23937da2899SCharles.Forsyth 	int size;
24037da2899SCharles.Forsyth 	Bhdr *tp, *t;
24137da2899SCharles.Forsyth 
24237da2899SCharles.Forsyth 	q->magic = MAGIC_F;
24337da2899SCharles.Forsyth 
24437da2899SCharles.Forsyth 	q->left = nil;
24537da2899SCharles.Forsyth 	q->right = nil;
24637da2899SCharles.Forsyth 	q->parent = nil;
24737da2899SCharles.Forsyth 	q->fwd = q;
24837da2899SCharles.Forsyth 	q->prev = q;
24937da2899SCharles.Forsyth 
25037da2899SCharles.Forsyth 	t = p->root;
25137da2899SCharles.Forsyth 	if(t == nil) {
25237da2899SCharles.Forsyth 		p->root = q;
25337da2899SCharles.Forsyth 		return;
25437da2899SCharles.Forsyth 	}
25537da2899SCharles.Forsyth 
25637da2899SCharles.Forsyth 	size = q->size;
25737da2899SCharles.Forsyth 
25837da2899SCharles.Forsyth 	tp = nil;
25937da2899SCharles.Forsyth 	while(t != nil) {
26037da2899SCharles.Forsyth 		if(size == t->size) {
26137da2899SCharles.Forsyth 			q->prev = t->prev;
26237da2899SCharles.Forsyth 			q->prev->fwd = q;
26337da2899SCharles.Forsyth 			q->fwd = t;
26437da2899SCharles.Forsyth 			t->prev = q;
26537da2899SCharles.Forsyth 			return;
26637da2899SCharles.Forsyth 		}
26737da2899SCharles.Forsyth 		tp = t;
26837da2899SCharles.Forsyth 		if(size < t->size)
26937da2899SCharles.Forsyth 			t = t->left;
27037da2899SCharles.Forsyth 		else
27137da2899SCharles.Forsyth 			t = t->right;
27237da2899SCharles.Forsyth 	}
27337da2899SCharles.Forsyth 
27437da2899SCharles.Forsyth 	q->parent = tp;
27537da2899SCharles.Forsyth 	if(size < tp->size)
27637da2899SCharles.Forsyth 		tp->left = q;
27737da2899SCharles.Forsyth 	else
27837da2899SCharles.Forsyth 		tp->right = q;
27937da2899SCharles.Forsyth }
28037da2899SCharles.Forsyth 
28137da2899SCharles.Forsyth static void*
dopoolalloc(Pool * p,ulong asize,ulong pc)28237da2899SCharles.Forsyth dopoolalloc(Pool *p, ulong asize, ulong pc)
28337da2899SCharles.Forsyth {
28437da2899SCharles.Forsyth 	Bhdr *q, *t;
28537da2899SCharles.Forsyth 	int alloc, ldr, ns, frag;
28637da2899SCharles.Forsyth 	int osize, size;
28737da2899SCharles.Forsyth 
28837da2899SCharles.Forsyth 	if(asize >= 1024*1024*1024)	/* for sanity and to avoid overflow */
28937da2899SCharles.Forsyth 		return nil;
29037da2899SCharles.Forsyth 	size = asize;
29137da2899SCharles.Forsyth 	osize = size;
29237da2899SCharles.Forsyth 	size = (size + BHDRSIZE + p->quanta) & ~(p->quanta);
29337da2899SCharles.Forsyth 
29437da2899SCharles.Forsyth 	lock(&p->l);
29537da2899SCharles.Forsyth 	p->nalloc++;
29637da2899SCharles.Forsyth 
29737da2899SCharles.Forsyth 	t = p->root;
29837da2899SCharles.Forsyth 	q = nil;
29937da2899SCharles.Forsyth 	while(t) {
30037da2899SCharles.Forsyth 		if(t->size == size) {
30137da2899SCharles.Forsyth 			t = t->fwd;
30237da2899SCharles.Forsyth 			pooldel(p, t);
30337da2899SCharles.Forsyth 			t->magic = MAGIC_A;
30437da2899SCharles.Forsyth 			p->cursize += t->size;
30537da2899SCharles.Forsyth 			if(p->cursize > p->hw)
30637da2899SCharles.Forsyth 				p->hw = p->cursize;
30737da2899SCharles.Forsyth 			unlock(&p->l);
30837da2899SCharles.Forsyth 			if(p->monitor)
30937da2899SCharles.Forsyth 				MM(p->pnum, pc, (ulong)B2D(t), size);
31037da2899SCharles.Forsyth 			return B2D(t);
31137da2899SCharles.Forsyth 		}
31237da2899SCharles.Forsyth 		if(size < t->size) {
31337da2899SCharles.Forsyth 			q = t;
31437da2899SCharles.Forsyth 			t = t->left;
31537da2899SCharles.Forsyth 		}
31637da2899SCharles.Forsyth 		else
31737da2899SCharles.Forsyth 			t = t->right;
31837da2899SCharles.Forsyth 	}
31937da2899SCharles.Forsyth 	if(q != nil) {
32037da2899SCharles.Forsyth 		pooldel(p, q);
32137da2899SCharles.Forsyth 		q->magic = MAGIC_A;
32237da2899SCharles.Forsyth 		frag = q->size - size;
32337da2899SCharles.Forsyth 		if(frag < (size>>2) && frag < 0x8000) {
32437da2899SCharles.Forsyth 			p->cursize += q->size;
32537da2899SCharles.Forsyth 			if(p->cursize > p->hw)
32637da2899SCharles.Forsyth 				p->hw = p->cursize;
32737da2899SCharles.Forsyth 			unlock(&p->l);
32837da2899SCharles.Forsyth 			if(p->monitor)
32937da2899SCharles.Forsyth 				MM(p->pnum, pc, (ulong)B2D(q), size);
33037da2899SCharles.Forsyth 			return B2D(q);
33137da2899SCharles.Forsyth 		}
33237da2899SCharles.Forsyth 		/* Split */
33337da2899SCharles.Forsyth 		ns = q->size - size;
33437da2899SCharles.Forsyth 		q->size = size;
33537da2899SCharles.Forsyth 		B2T(q)->hdr = q;
33637da2899SCharles.Forsyth 		t = B2NB(q);
33737da2899SCharles.Forsyth 		t->size = ns;
33837da2899SCharles.Forsyth 		B2T(t)->hdr = t;
33937da2899SCharles.Forsyth 		pooladd(p, t);
34037da2899SCharles.Forsyth 		p->cursize += q->size;
34137da2899SCharles.Forsyth 		if(p->cursize > p->hw)
34237da2899SCharles.Forsyth 			p->hw = p->cursize;
34337da2899SCharles.Forsyth 		unlock(&p->l);
34437da2899SCharles.Forsyth 		if(p->monitor)
34537da2899SCharles.Forsyth 			MM(p->pnum, pc, (ulong)B2D(q), size);
34637da2899SCharles.Forsyth 		return B2D(q);
34737da2899SCharles.Forsyth 	}
34837da2899SCharles.Forsyth 
34937da2899SCharles.Forsyth 	ns = p->chunk;
35037da2899SCharles.Forsyth 	if(size > ns)
35137da2899SCharles.Forsyth 		ns = size;
35237da2899SCharles.Forsyth 	ldr = p->quanta+1;
35337da2899SCharles.Forsyth 
35437da2899SCharles.Forsyth 	alloc = ns+ldr+ldr;
35537da2899SCharles.Forsyth 	p->arenasize += alloc;
35637da2899SCharles.Forsyth 	if(p->arenasize > p->maxsize) {
35737da2899SCharles.Forsyth 		p->arenasize -= alloc;
35837da2899SCharles.Forsyth 		ns = p->maxsize-p->arenasize-ldr-ldr;
35937da2899SCharles.Forsyth 		ns &= ~p->quanta;
36037da2899SCharles.Forsyth 		if (ns < size) {
36137da2899SCharles.Forsyth 			if(poolcompact(p)) {
36237da2899SCharles.Forsyth 				unlock(&p->l);
36337da2899SCharles.Forsyth 				return poolalloc(p, osize);
36437da2899SCharles.Forsyth 			}
36537da2899SCharles.Forsyth 
36637da2899SCharles.Forsyth 			unlock(&p->l);
36737da2899SCharles.Forsyth 			print("arena %s too large: size %d cursize %lud arenasize %lud maxsize %lud\n",
36837da2899SCharles.Forsyth 			 p->name, size, p->cursize, p->arenasize, p->maxsize);
36937da2899SCharles.Forsyth 			return nil;
37037da2899SCharles.Forsyth 		}
37137da2899SCharles.Forsyth 		alloc = ns+ldr+ldr;
37237da2899SCharles.Forsyth 		p->arenasize += alloc;
37337da2899SCharles.Forsyth 	}
37437da2899SCharles.Forsyth 
37537da2899SCharles.Forsyth 	p->nbrk++;
37637da2899SCharles.Forsyth 	t = (Bhdr *)sbrk(alloc);
37737da2899SCharles.Forsyth 	if(t == (void*)-1) {
37837da2899SCharles.Forsyth 		p->nbrk--;
37937da2899SCharles.Forsyth 		unlock(&p->l);
38037da2899SCharles.Forsyth 		return nil;
38137da2899SCharles.Forsyth 	}
382*bea7f0ccSValery Ushakov #ifdef __NetBSD__
383*bea7f0ccSValery Ushakov 	/* Align allocations to 16 bytes */
384*bea7f0ccSValery Ushakov 	{
385*bea7f0ccSValery Ushakov 		const size_t off = __builtin_offsetof(struct Bhdr, u.data)
386*bea7f0ccSValery Ushakov 					+ Npadlong*sizeof(ulong);
387*bea7f0ccSValery Ushakov 		struct assert_align {
388*bea7f0ccSValery Ushakov 			unsigned int align_ok : (off % 8 == 0) ? 1 : -1;
389*bea7f0ccSValery Ushakov 		};
390*bea7f0ccSValery Ushakov 
391*bea7f0ccSValery Ushakov 		const ulong align = (off - 1) % 16;
392*bea7f0ccSValery Ushakov 		t = (Bhdr *)(((ulong)t + align) & ~align);
393*bea7f0ccSValery Ushakov 	}
394*bea7f0ccSValery Ushakov #else
39537da2899SCharles.Forsyth 	/* Double alignment */
39637da2899SCharles.Forsyth 	t = (Bhdr *)(((ulong)t + 7) & ~7);
397*bea7f0ccSValery Ushakov #endif
39837da2899SCharles.Forsyth 	if(p->chain != nil && (char*)t-(char*)B2LIMIT(p->chain)-ldr == 0){
39937da2899SCharles.Forsyth 		/* can merge chains */
40037da2899SCharles.Forsyth 		if(0)print("merging chains %p and %p in %s\n", p->chain, t, p->name);
40137da2899SCharles.Forsyth 		q = B2LIMIT(p->chain);
40237da2899SCharles.Forsyth 		q->magic = MAGIC_A;
40337da2899SCharles.Forsyth 		q->size = alloc;
40437da2899SCharles.Forsyth 		B2T(q)->hdr = q;
40537da2899SCharles.Forsyth 		t = B2NB(q);
40637da2899SCharles.Forsyth 		t->magic = MAGIC_E;
40737da2899SCharles.Forsyth 		p->chain->csize += alloc;
40837da2899SCharles.Forsyth 		p->cursize += alloc;
40937da2899SCharles.Forsyth 		unlock(&p->l);
41037da2899SCharles.Forsyth 		poolfree(p, B2D(q));		/* for backward merge */
41137da2899SCharles.Forsyth 		return poolalloc(p, osize);
41237da2899SCharles.Forsyth 	}
41337da2899SCharles.Forsyth 
41437da2899SCharles.Forsyth 	t->magic = MAGIC_E;		/* Make a leader */
41537da2899SCharles.Forsyth 	t->size = ldr;
41637da2899SCharles.Forsyth 	t->csize = ns+ldr;
41737da2899SCharles.Forsyth 	t->clink = p->chain;
41837da2899SCharles.Forsyth 	p->chain = t;
41937da2899SCharles.Forsyth 	B2T(t)->hdr = t;
42037da2899SCharles.Forsyth 	t = B2NB(t);
42137da2899SCharles.Forsyth 
42237da2899SCharles.Forsyth 	t->magic = MAGIC_A;		/* Make the block we are going to return */
42337da2899SCharles.Forsyth 	t->size = size;
42437da2899SCharles.Forsyth 	B2T(t)->hdr = t;
42537da2899SCharles.Forsyth 	q = t;
42637da2899SCharles.Forsyth 
42737da2899SCharles.Forsyth 	ns -= size;			/* Free the rest */
42837da2899SCharles.Forsyth 	if(ns > 0) {
42937da2899SCharles.Forsyth 		q = B2NB(t);
43037da2899SCharles.Forsyth 		q->size = ns;
43137da2899SCharles.Forsyth 		B2T(q)->hdr = q;
43237da2899SCharles.Forsyth 		pooladd(p, q);
43337da2899SCharles.Forsyth 	}
43437da2899SCharles.Forsyth 	B2NB(q)->magic = MAGIC_E;	/* Mark the end of the chunk */
43537da2899SCharles.Forsyth 
43637da2899SCharles.Forsyth 	p->cursize += t->size;
43737da2899SCharles.Forsyth 	if(p->cursize > p->hw)
43837da2899SCharles.Forsyth 		p->hw = p->cursize;
43937da2899SCharles.Forsyth 	unlock(&p->l);
44037da2899SCharles.Forsyth 	if(p->monitor)
44137da2899SCharles.Forsyth 		MM(p->pnum, pc, (ulong)B2D(t), size);
44237da2899SCharles.Forsyth 	return B2D(t);
44337da2899SCharles.Forsyth }
44437da2899SCharles.Forsyth 
44537da2899SCharles.Forsyth void *
poolalloc(Pool * p,ulong asize)44637da2899SCharles.Forsyth poolalloc(Pool *p, ulong asize)
44737da2899SCharles.Forsyth {
44837da2899SCharles.Forsyth 	Prog *prog;
44937da2899SCharles.Forsyth 
45037da2899SCharles.Forsyth 	if(p->cursize > p->ressize && (prog = currun()) != nil && prog->flags&Prestricted)
45137da2899SCharles.Forsyth 		return nil;
45237da2899SCharles.Forsyth 	return dopoolalloc(p, asize, getcallerpc(&p));
45337da2899SCharles.Forsyth }
45437da2899SCharles.Forsyth 
45537da2899SCharles.Forsyth void
poolfree(Pool * p,void * v)45637da2899SCharles.Forsyth poolfree(Pool *p, void *v)
45737da2899SCharles.Forsyth {
45837da2899SCharles.Forsyth 	Bhdr *b, *c;
45937da2899SCharles.Forsyth 	extern Bhdr *ptr;
46037da2899SCharles.Forsyth 
46137da2899SCharles.Forsyth 	D2B(b, v);
46237da2899SCharles.Forsyth 	if(p->monitor)
46337da2899SCharles.Forsyth 		MM(p->pnum|(1<<8), getcallerpc(&p), (ulong)v, b->size);
46437da2899SCharles.Forsyth 
46537da2899SCharles.Forsyth 	lock(&p->l);
46637da2899SCharles.Forsyth 	p->nfree++;
46737da2899SCharles.Forsyth 	p->cursize -= b->size;
46837da2899SCharles.Forsyth 	c = B2NB(b);
46937da2899SCharles.Forsyth 	if(c->magic == MAGIC_F) {	/* Join forward */
47037da2899SCharles.Forsyth 		if(c == ptr)
47137da2899SCharles.Forsyth 			ptr = b;
47237da2899SCharles.Forsyth 		pooldel(p, c);
47337da2899SCharles.Forsyth 		c->magic = 0;
47437da2899SCharles.Forsyth 		b->size += c->size;
47537da2899SCharles.Forsyth 		B2T(b)->hdr = b;
47637da2899SCharles.Forsyth 	}
47737da2899SCharles.Forsyth 
47837da2899SCharles.Forsyth 	c = B2PT(b)->hdr;
47937da2899SCharles.Forsyth 	if(c->magic == MAGIC_F) {	/* Join backward */
48037da2899SCharles.Forsyth 		if(b == ptr)
48137da2899SCharles.Forsyth 			ptr = c;
48237da2899SCharles.Forsyth 		pooldel(p, c);
48337da2899SCharles.Forsyth 		b->magic = 0;
48437da2899SCharles.Forsyth 		c->size += b->size;
48537da2899SCharles.Forsyth 		b = c;
48637da2899SCharles.Forsyth 		B2T(b)->hdr = b;
48737da2899SCharles.Forsyth 	}
48837da2899SCharles.Forsyth 	pooladd(p, b);
48937da2899SCharles.Forsyth 	unlock(&p->l);
49037da2899SCharles.Forsyth }
49137da2899SCharles.Forsyth 
49237da2899SCharles.Forsyth void *
poolrealloc(Pool * p,void * v,ulong size)49337da2899SCharles.Forsyth poolrealloc(Pool *p, void *v, ulong size)
49437da2899SCharles.Forsyth {
49537da2899SCharles.Forsyth 	Bhdr *b;
49637da2899SCharles.Forsyth 	void *nv;
49737da2899SCharles.Forsyth 	int osize;
49837da2899SCharles.Forsyth 
49937da2899SCharles.Forsyth 	if(size >= 1024*1024*1024)	/* for sanity and to avoid overflow */
50037da2899SCharles.Forsyth 		return nil;
50137da2899SCharles.Forsyth 	if(size == 0){
50237da2899SCharles.Forsyth 		poolfree(p, v);
50337da2899SCharles.Forsyth 		return nil;
50437da2899SCharles.Forsyth 	}
50537da2899SCharles.Forsyth 	SET(osize);
50637da2899SCharles.Forsyth 	if(v != nil){
50737da2899SCharles.Forsyth 		lock(&p->l);
50837da2899SCharles.Forsyth 		D2B(b, v);
50937da2899SCharles.Forsyth 		osize = b->size - BHDRSIZE;
51037da2899SCharles.Forsyth 		unlock(&p->l);
51137da2899SCharles.Forsyth 		if(osize >= size)
51237da2899SCharles.Forsyth 			return v;
51337da2899SCharles.Forsyth 	}
51437da2899SCharles.Forsyth 	nv = poolalloc(p, size);
51537da2899SCharles.Forsyth 	if(nv != nil && v != nil){
51637da2899SCharles.Forsyth 		memmove(nv, v, osize);
51737da2899SCharles.Forsyth 		poolfree(p, v);
51837da2899SCharles.Forsyth 	}
51937da2899SCharles.Forsyth 	return nv;
52037da2899SCharles.Forsyth }
52137da2899SCharles.Forsyth 
52237da2899SCharles.Forsyth ulong
poolmsize(Pool * p,void * v)52337da2899SCharles.Forsyth poolmsize(Pool *p, void *v)
52437da2899SCharles.Forsyth {
52537da2899SCharles.Forsyth 	Bhdr *b;
52637da2899SCharles.Forsyth 	ulong size;
52737da2899SCharles.Forsyth 
52837da2899SCharles.Forsyth 	if(v == nil)
52937da2899SCharles.Forsyth 		return 0;
53037da2899SCharles.Forsyth 	lock(&p->l);
53137da2899SCharles.Forsyth 	D2B(b, v);
53237da2899SCharles.Forsyth 	size = b->size - BHDRSIZE;
53337da2899SCharles.Forsyth 	unlock(&p->l);
53437da2899SCharles.Forsyth 	return size;
53537da2899SCharles.Forsyth }
53637da2899SCharles.Forsyth 
53737da2899SCharles.Forsyth static ulong
poolmax(Pool * p)53837da2899SCharles.Forsyth poolmax(Pool *p)
53937da2899SCharles.Forsyth {
54037da2899SCharles.Forsyth 	Bhdr *t;
54137da2899SCharles.Forsyth 	ulong size;
54237da2899SCharles.Forsyth 
54337da2899SCharles.Forsyth 	lock(&p->l);
54437da2899SCharles.Forsyth 	size = p->maxsize - p->cursize;
54537da2899SCharles.Forsyth 	t = p->root;
54637da2899SCharles.Forsyth 	if(t != nil) {
54737da2899SCharles.Forsyth 		while(t->right != nil)
54837da2899SCharles.Forsyth 			t = t->right;
54937da2899SCharles.Forsyth 		if(size < t->size)
55037da2899SCharles.Forsyth 			size = t->size;
55137da2899SCharles.Forsyth 	}
55237da2899SCharles.Forsyth 	if(size >= BHDRSIZE)
55337da2899SCharles.Forsyth 		size -= BHDRSIZE;
55437da2899SCharles.Forsyth 	unlock(&p->l);
55537da2899SCharles.Forsyth 	return size;
55637da2899SCharles.Forsyth }
55737da2899SCharles.Forsyth 
55837da2899SCharles.Forsyth ulong
poolmaxsize(void)55937da2899SCharles.Forsyth poolmaxsize(void)
56037da2899SCharles.Forsyth {
56137da2899SCharles.Forsyth 	int i;
56237da2899SCharles.Forsyth 	ulong total;
56337da2899SCharles.Forsyth 
56437da2899SCharles.Forsyth 	total = 0;
56537da2899SCharles.Forsyth 	for(i = 0; i < nelem(table.pool); i++)
56637da2899SCharles.Forsyth 		total += table.pool[i].maxsize;
56737da2899SCharles.Forsyth 	return total;
56837da2899SCharles.Forsyth }
56937da2899SCharles.Forsyth 
57037da2899SCharles.Forsyth int
poolread(char * va,int count,ulong offset)57137da2899SCharles.Forsyth poolread(char *va, int count, ulong offset)
57237da2899SCharles.Forsyth {
57337da2899SCharles.Forsyth 	Pool *p;
57437da2899SCharles.Forsyth 	int n, i, signed_off;
57537da2899SCharles.Forsyth 
57637da2899SCharles.Forsyth 	n = 0;
57737da2899SCharles.Forsyth 	signed_off = offset;
57837da2899SCharles.Forsyth 	for(i = 0; i < table.n; i++) {
57937da2899SCharles.Forsyth 		p = &table.pool[i];
58037da2899SCharles.Forsyth 		n += snprint(va+n, count-n, "%11lud %11lud %11lud %11lud %11lud %11d %11lud %s\n",
58137da2899SCharles.Forsyth 			p->cursize,
58237da2899SCharles.Forsyth 			p->maxsize,
58337da2899SCharles.Forsyth 			p->hw,
58437da2899SCharles.Forsyth 			p->nalloc,
58537da2899SCharles.Forsyth 			p->nfree,
58637da2899SCharles.Forsyth 			p->nbrk,
58737da2899SCharles.Forsyth 			poolmax(p),
58837da2899SCharles.Forsyth 			p->name);
58937da2899SCharles.Forsyth 
59037da2899SCharles.Forsyth 		if(signed_off > 0) {
59137da2899SCharles.Forsyth 			signed_off -= n;
59237da2899SCharles.Forsyth 			if(signed_off < 0) {
59337da2899SCharles.Forsyth 				memmove(va, va+n+signed_off, -signed_off);
59437da2899SCharles.Forsyth 				n = -signed_off;
59537da2899SCharles.Forsyth 			}
59637da2899SCharles.Forsyth 			else
59737da2899SCharles.Forsyth 				n = 0;
59837da2899SCharles.Forsyth 		}
59937da2899SCharles.Forsyth 
60037da2899SCharles.Forsyth 	}
60137da2899SCharles.Forsyth 	return n;
60237da2899SCharles.Forsyth }
60337da2899SCharles.Forsyth 
60437da2899SCharles.Forsyth void*
smalloc(size_t size)60537da2899SCharles.Forsyth smalloc(size_t size)
60637da2899SCharles.Forsyth {
60737da2899SCharles.Forsyth 	void *v;
60837da2899SCharles.Forsyth 
60937da2899SCharles.Forsyth 	for(;;){
61037da2899SCharles.Forsyth 		v = malloc(size);
61137da2899SCharles.Forsyth 		if(v != nil)
61237da2899SCharles.Forsyth 			break;
61337da2899SCharles.Forsyth 		if(0)
61437da2899SCharles.Forsyth 			print("smalloc waiting from %lux\n", getcallerpc(&size));
61537da2899SCharles.Forsyth 		osenter();
61637da2899SCharles.Forsyth 		osmillisleep(100);
61737da2899SCharles.Forsyth 		osleave();
61837da2899SCharles.Forsyth 	}
61937da2899SCharles.Forsyth 	setmalloctag(v, getcallerpc(&size));
62037da2899SCharles.Forsyth 	setrealloctag(v, 0);
62137da2899SCharles.Forsyth 	return v;
62237da2899SCharles.Forsyth }
62337da2899SCharles.Forsyth 
62437da2899SCharles.Forsyth void*
kmalloc(size_t size)62537da2899SCharles.Forsyth kmalloc(size_t size)
62637da2899SCharles.Forsyth {
62737da2899SCharles.Forsyth 	void *v;
62837da2899SCharles.Forsyth 
62937da2899SCharles.Forsyth 	v = dopoolalloc(mainmem, size+Npadlong*sizeof(ulong), getcallerpc(&size));
63037da2899SCharles.Forsyth 	if(v != nil){
63137da2899SCharles.Forsyth 		ML(v, size, getcallerpc(&size));
63237da2899SCharles.Forsyth 		if(Npadlong){
63337da2899SCharles.Forsyth 			v = (ulong*)v+Npadlong;
63437da2899SCharles.Forsyth 			setmalloctag(v, getcallerpc(&size));
63537da2899SCharles.Forsyth 			setrealloctag(v, 0);
63637da2899SCharles.Forsyth 		}
63737da2899SCharles.Forsyth 		memset(v, 0, size);
63837da2899SCharles.Forsyth 		MM(0, getcallerpc(&size), (ulong)v, size);
63937da2899SCharles.Forsyth 	}
64037da2899SCharles.Forsyth 	return v;
64137da2899SCharles.Forsyth }
64237da2899SCharles.Forsyth 
64337da2899SCharles.Forsyth 
64437da2899SCharles.Forsyth 
64537da2899SCharles.Forsyth void*
malloc(size_t size)64637da2899SCharles.Forsyth malloc(size_t size)
64737da2899SCharles.Forsyth {
64837da2899SCharles.Forsyth 	void *v;
64937da2899SCharles.Forsyth 
65037da2899SCharles.Forsyth 	v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
65137da2899SCharles.Forsyth 	if(v != nil){
65237da2899SCharles.Forsyth 		ML(v, size, getcallerpc(&size));
65337da2899SCharles.Forsyth 		if(Npadlong){
65437da2899SCharles.Forsyth 			v = (ulong*)v+Npadlong;
65537da2899SCharles.Forsyth 			setmalloctag(v, getcallerpc(&size));
65637da2899SCharles.Forsyth 			setrealloctag(v, 0);
65737da2899SCharles.Forsyth 		}
65837da2899SCharles.Forsyth 		memset(v, 0, size);
65937da2899SCharles.Forsyth 		MM(0, getcallerpc(&size), (ulong)v, size);
66037da2899SCharles.Forsyth 	} else
66137da2899SCharles.Forsyth 		print("malloc failed from %lux\n", getcallerpc(&size));
66237da2899SCharles.Forsyth 	return v;
66337da2899SCharles.Forsyth }
66437da2899SCharles.Forsyth 
66537da2899SCharles.Forsyth void*
mallocz(ulong size,int clr)66637da2899SCharles.Forsyth mallocz(ulong size, int clr)
66737da2899SCharles.Forsyth {
66837da2899SCharles.Forsyth 	void *v;
66937da2899SCharles.Forsyth 
67037da2899SCharles.Forsyth 	v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
67137da2899SCharles.Forsyth 	if(v != nil){
67237da2899SCharles.Forsyth 		ML(v, size, getcallerpc(&size));
67337da2899SCharles.Forsyth 		if(Npadlong){
67437da2899SCharles.Forsyth 			v = (ulong*)v+Npadlong;
67537da2899SCharles.Forsyth 			setmalloctag(v, getcallerpc(&size));
67637da2899SCharles.Forsyth 			setrealloctag(v, 0);
67737da2899SCharles.Forsyth 		}
67837da2899SCharles.Forsyth 		if(clr)
67937da2899SCharles.Forsyth 			memset(v, 0, size);
68037da2899SCharles.Forsyth 		MM(0, getcallerpc(&size), (ulong)v, size);
68137da2899SCharles.Forsyth 	} else
68237da2899SCharles.Forsyth 		print("mallocz failed from %lux\n", getcallerpc(&size));
68337da2899SCharles.Forsyth 	return v;
68437da2899SCharles.Forsyth }
68537da2899SCharles.Forsyth 
68637da2899SCharles.Forsyth void
free(void * v)68737da2899SCharles.Forsyth free(void *v)
68837da2899SCharles.Forsyth {
68937da2899SCharles.Forsyth 	Bhdr *b;
69037da2899SCharles.Forsyth 
69137da2899SCharles.Forsyth 	if(v != nil) {
69237da2899SCharles.Forsyth 		if(Npadlong)
69337da2899SCharles.Forsyth 			v = (ulong*)v-Npadlong;
69437da2899SCharles.Forsyth 		D2B(b, v);
69537da2899SCharles.Forsyth 		ML(v, 0, 0);
69637da2899SCharles.Forsyth 		MM(1<<8|0, getcallerpc(&v), (ulong)((ulong*)v+Npadlong), b->size);
69737da2899SCharles.Forsyth 		poolfree(mainmem, v);
69837da2899SCharles.Forsyth 	}
69937da2899SCharles.Forsyth }
70037da2899SCharles.Forsyth 
70137da2899SCharles.Forsyth void*
realloc(void * v,size_t size)70237da2899SCharles.Forsyth realloc(void *v, size_t size)
70337da2899SCharles.Forsyth {
70437da2899SCharles.Forsyth 	void *nv;
70537da2899SCharles.Forsyth 
70637da2899SCharles.Forsyth 	if(size == 0)
70737da2899SCharles.Forsyth 		return malloc(size);	/* temporary change until realloc calls can be checked */
70837da2899SCharles.Forsyth 	if(v != nil)
70937da2899SCharles.Forsyth 		v = (ulong*)v-Npadlong;
71037da2899SCharles.Forsyth 	if(Npadlong!=0 && size!=0)
71137da2899SCharles.Forsyth 		size += Npadlong*sizeof(ulong);
71237da2899SCharles.Forsyth 	nv = poolrealloc(mainmem, v, size);
71337da2899SCharles.Forsyth 	ML(v, 0, 0);
71437da2899SCharles.Forsyth 	ML(nv, size, getcallerpc(&v));
71537da2899SCharles.Forsyth 	if(nv != nil) {
71637da2899SCharles.Forsyth 		nv = (ulong*)nv+Npadlong;
71737da2899SCharles.Forsyth 		setrealloctag(nv, getcallerpc(&v));
71837da2899SCharles.Forsyth 		if(v == nil)
71937da2899SCharles.Forsyth 			setmalloctag(v, getcallerpc(&v));
72037da2899SCharles.Forsyth 	} else
72137da2899SCharles.Forsyth 		print("realloc failed from %lux\n", getcallerpc(&v));
72237da2899SCharles.Forsyth 	return nv;
72337da2899SCharles.Forsyth }
72437da2899SCharles.Forsyth 
72537da2899SCharles.Forsyth void
setmalloctag(void * v,ulong pc)72637da2899SCharles.Forsyth setmalloctag(void *v, ulong pc)
72737da2899SCharles.Forsyth {
72837da2899SCharles.Forsyth 	ulong *u;
72937da2899SCharles.Forsyth 
73037da2899SCharles.Forsyth 	USED(v);
73137da2899SCharles.Forsyth 	USED(pc);
73237da2899SCharles.Forsyth 	if(Npadlong <= MallocOffset || v == nil)
73337da2899SCharles.Forsyth 		return;
73437da2899SCharles.Forsyth 	u = v;
73537da2899SCharles.Forsyth 	u[-Npadlong+MallocOffset] = pc;
73637da2899SCharles.Forsyth }
73737da2899SCharles.Forsyth 
73837da2899SCharles.Forsyth ulong
getmalloctag(void * v)73937da2899SCharles.Forsyth getmalloctag(void *v)
74037da2899SCharles.Forsyth {
74137da2899SCharles.Forsyth 	USED(v);
74237da2899SCharles.Forsyth 	if(Npadlong <= MallocOffset)
74337da2899SCharles.Forsyth 		return ~0;
74437da2899SCharles.Forsyth 	return ((ulong*)v)[-Npadlong+MallocOffset];
74537da2899SCharles.Forsyth }
74637da2899SCharles.Forsyth 
74737da2899SCharles.Forsyth void
setrealloctag(void * v,ulong pc)74837da2899SCharles.Forsyth setrealloctag(void *v, ulong pc)
74937da2899SCharles.Forsyth {
75037da2899SCharles.Forsyth 	ulong *u;
75137da2899SCharles.Forsyth 
75237da2899SCharles.Forsyth 	USED(v);
75337da2899SCharles.Forsyth 	USED(pc);
75437da2899SCharles.Forsyth 	if(Npadlong <= ReallocOffset || v == nil)
75537da2899SCharles.Forsyth 		return;
75637da2899SCharles.Forsyth 	u = v;
75737da2899SCharles.Forsyth 	u[-Npadlong+ReallocOffset] = pc;
75837da2899SCharles.Forsyth }
75937da2899SCharles.Forsyth 
76037da2899SCharles.Forsyth ulong
getrealloctag(void * v)76137da2899SCharles.Forsyth getrealloctag(void *v)
76237da2899SCharles.Forsyth {
76337da2899SCharles.Forsyth 	USED(v);
76437da2899SCharles.Forsyth 	if(Npadlong <= ReallocOffset)
76537da2899SCharles.Forsyth 		return ((ulong*)v)[-Npadlong+ReallocOffset];
76637da2899SCharles.Forsyth 	return ~0;
76737da2899SCharles.Forsyth }
76837da2899SCharles.Forsyth 
76937da2899SCharles.Forsyth ulong
msize(void * v)77037da2899SCharles.Forsyth msize(void *v)
77137da2899SCharles.Forsyth {
77237da2899SCharles.Forsyth 	if(v == nil)
77337da2899SCharles.Forsyth 		return 0;
77437da2899SCharles.Forsyth 	return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
77537da2899SCharles.Forsyth }
77637da2899SCharles.Forsyth 
77737da2899SCharles.Forsyth void*
calloc(size_t n,size_t szelem)77837da2899SCharles.Forsyth calloc(size_t n, size_t szelem)
77937da2899SCharles.Forsyth {
78037da2899SCharles.Forsyth 	return malloc(n*szelem);
78137da2899SCharles.Forsyth }
78237da2899SCharles.Forsyth 
78337da2899SCharles.Forsyth /*
78437da2899SCharles.Forsyth void
78537da2899SCharles.Forsyth pooldump(Pool *p)
78637da2899SCharles.Forsyth {
78737da2899SCharles.Forsyth 	Bhdr *b, *base, *limit, *ptr;
78837da2899SCharles.Forsyth 
78937da2899SCharles.Forsyth 	b = p->chain;
79037da2899SCharles.Forsyth 	if(b == nil)
79137da2899SCharles.Forsyth 		return;
79237da2899SCharles.Forsyth 	base = b;
79337da2899SCharles.Forsyth 	ptr = b;
79437da2899SCharles.Forsyth 	limit = B2LIMIT(b);
79537da2899SCharles.Forsyth 
79637da2899SCharles.Forsyth 	while(base != nil) {
79737da2899SCharles.Forsyth 		print("\tbase #%.8lux ptr #%.8lux", base, ptr);
79837da2899SCharles.Forsyth 		if(ptr->magic == MAGIC_A || ptr->magic == MAGIC_I)
79937da2899SCharles.Forsyth 			print("\tA%.5d\n", ptr->size);
80037da2899SCharles.Forsyth 		else if(ptr->magic == MAGIC_E)
80137da2899SCharles.Forsyth 			print("\tE\tL#%.8lux\tS#%.8lux\n", ptr->clink, ptr->csize);
80237da2899SCharles.Forsyth 		else
80337da2899SCharles.Forsyth 			print("\tF%.5d\tL#%.8lux\tR#%.8lux\tF#%.8lux\tP#%.8lux\tT#%.8lux\n",
80437da2899SCharles.Forsyth 				ptr->size, ptr->left, ptr->right, ptr->fwd, ptr->prev, ptr->parent);
80537da2899SCharles.Forsyth 		ptr = B2NB(ptr);
80637da2899SCharles.Forsyth 		if(ptr >= limit) {
80737da2899SCharles.Forsyth 			print("link to #%.8lux\n", base->clink);
80837da2899SCharles.Forsyth 			base = base->clink;
80937da2899SCharles.Forsyth 			if(base == nil)
81037da2899SCharles.Forsyth 				break;
81137da2899SCharles.Forsyth 			ptr = base;
81237da2899SCharles.Forsyth 			limit = B2LIMIT(base);
81337da2899SCharles.Forsyth 		}
81437da2899SCharles.Forsyth 	}
81537da2899SCharles.Forsyth }
81637da2899SCharles.Forsyth */
81737da2899SCharles.Forsyth 
81837da2899SCharles.Forsyth void
poolsetcompact(Pool * p,void (* move)(void *,void *))81937da2899SCharles.Forsyth poolsetcompact(Pool *p, void (*move)(void*, void*))
82037da2899SCharles.Forsyth {
82137da2899SCharles.Forsyth 	p->move = move;
82237da2899SCharles.Forsyth }
82337da2899SCharles.Forsyth 
82437da2899SCharles.Forsyth int
poolcompact(Pool * pool)82537da2899SCharles.Forsyth poolcompact(Pool *pool)
82637da2899SCharles.Forsyth {
82737da2899SCharles.Forsyth 	Bhdr *base, *limit, *ptr, *end, *next;
82837da2899SCharles.Forsyth 	int compacted, nb;
82937da2899SCharles.Forsyth 
83037da2899SCharles.Forsyth 	if(pool->move == nil || pool->lastfree == pool->nfree)
83137da2899SCharles.Forsyth 		return 0;
83237da2899SCharles.Forsyth 
83337da2899SCharles.Forsyth 	pool->lastfree = pool->nfree;
83437da2899SCharles.Forsyth 
83537da2899SCharles.Forsyth 	base = pool->chain;
83637da2899SCharles.Forsyth 	ptr = B2NB(base);	/* First Block in arena has clink */
83737da2899SCharles.Forsyth 	limit = B2LIMIT(base);
83837da2899SCharles.Forsyth 	compacted = 0;
83937da2899SCharles.Forsyth 
84037da2899SCharles.Forsyth 	pool->root = nil;
84137da2899SCharles.Forsyth 	end = ptr;
84237da2899SCharles.Forsyth 	while(base != nil) {
84337da2899SCharles.Forsyth 		next = B2NB(ptr);
84437da2899SCharles.Forsyth 		if(ptr->magic == MAGIC_A || ptr->magic == MAGIC_I) {
84537da2899SCharles.Forsyth 			if(ptr != end) {
84637da2899SCharles.Forsyth 				memmove(end, ptr, ptr->size);
84737da2899SCharles.Forsyth 				pool->move(B2D(ptr), B2D(end));
84837da2899SCharles.Forsyth 				compacted = 1;
84937da2899SCharles.Forsyth 			}
85037da2899SCharles.Forsyth 			end = B2NB(end);
85137da2899SCharles.Forsyth 		}
85237da2899SCharles.Forsyth 		if(next >= limit) {
85337da2899SCharles.Forsyth 			nb = (uchar*)limit - (uchar*)end;
85437da2899SCharles.Forsyth 			if(nb > 0){
85537da2899SCharles.Forsyth 				if(nb < pool->quanta+1){
85637da2899SCharles.Forsyth 					print("poolcompact: leftover too small\n");
85737da2899SCharles.Forsyth 					abort();
85837da2899SCharles.Forsyth 				}
85937da2899SCharles.Forsyth 				end->size = nb;
86037da2899SCharles.Forsyth 				B2T(end)->hdr = end;
86137da2899SCharles.Forsyth 				pooladd(pool, end);
86237da2899SCharles.Forsyth 			}
86337da2899SCharles.Forsyth 			base = base->clink;
86437da2899SCharles.Forsyth 			if(base == nil)
86537da2899SCharles.Forsyth 				break;
86637da2899SCharles.Forsyth 			ptr = B2NB(base);
86737da2899SCharles.Forsyth 			end = ptr;	/* could do better by copying between chains */
86837da2899SCharles.Forsyth 			limit = B2LIMIT(base);
86937da2899SCharles.Forsyth 		} else
87037da2899SCharles.Forsyth 			ptr = next;
87137da2899SCharles.Forsyth 	}
87237da2899SCharles.Forsyth 
87337da2899SCharles.Forsyth 	return compacted;
87437da2899SCharles.Forsyth }
87537da2899SCharles.Forsyth 
87637da2899SCharles.Forsyth static void
_poolfault(void * v,char * msg,ulong c)87737da2899SCharles.Forsyth _poolfault(void *v, char *msg, ulong c)
87837da2899SCharles.Forsyth {
87937da2899SCharles.Forsyth 	auditmemloc(msg, v);
88037da2899SCharles.Forsyth 	panic("%s %lux (from %lux/%lux)", msg, v, getcallerpc(&v), c);
88137da2899SCharles.Forsyth }
88237da2899SCharles.Forsyth 
88337da2899SCharles.Forsyth static void
dumpvl(char * msg,ulong * v,int n)88437da2899SCharles.Forsyth dumpvl(char *msg, ulong *v, int n)
88537da2899SCharles.Forsyth {
88637da2899SCharles.Forsyth 	int i, l;
88737da2899SCharles.Forsyth 
88837da2899SCharles.Forsyth 	l = print("%s at %p: ", msg, v);
88937da2899SCharles.Forsyth 	for (i = 0; i < n; i++) {
89037da2899SCharles.Forsyth 		if (l >= 60) {
89137da2899SCharles.Forsyth 			print("\n");
89237da2899SCharles.Forsyth 			l = print("    %p: ", v);
89337da2899SCharles.Forsyth 		}
89437da2899SCharles.Forsyth 		l += print(" %lux", *v++);
89537da2899SCharles.Forsyth 	}
89637da2899SCharles.Forsyth 	print("\n");
89737da2899SCharles.Forsyth }
89837da2899SCharles.Forsyth 
89937da2899SCharles.Forsyth static void
corrupted(char * str,char * msg,Pool * p,Bhdr * b,void * v)90037da2899SCharles.Forsyth corrupted(char *str, char *msg, Pool *p, Bhdr *b, void *v)
90137da2899SCharles.Forsyth {
90237da2899SCharles.Forsyth 	print("%s(%p): pool %s CORRUPT: %s at %p'%lud(magic=%lux)\n",
90337da2899SCharles.Forsyth 		str, v, p->name, msg, b, b->size, b->magic);
90437da2899SCharles.Forsyth 	dumpvl("bad Bhdr", (ulong *)((ulong)b & ~3)-4, 10);
90537da2899SCharles.Forsyth }
90637da2899SCharles.Forsyth 
90737da2899SCharles.Forsyth static void
_auditmemloc(char * str,void * v)90837da2899SCharles.Forsyth _auditmemloc(char *str, void *v)
90937da2899SCharles.Forsyth {
91037da2899SCharles.Forsyth 	Pool *p;
91137da2899SCharles.Forsyth 	Bhdr *bc, *ec, *b, *nb, *fb = nil;
91237da2899SCharles.Forsyth 	char *fmsg, *msg;
91337da2899SCharles.Forsyth 	ulong fsz;
91437da2899SCharles.Forsyth 
91537da2899SCharles.Forsyth 	SET(fsz);
91637da2899SCharles.Forsyth 	SET(fmsg);
91737da2899SCharles.Forsyth 	for (p = &table.pool[0]; p < &table.pool[nelem(table.pool)]; p++) {
91837da2899SCharles.Forsyth 		lock(&p->l);
91937da2899SCharles.Forsyth 		for (bc = p->chain; bc != nil; bc = bc->clink) {
92037da2899SCharles.Forsyth 			if (bc->magic != MAGIC_E) {
92137da2899SCharles.Forsyth 				unlock(&p->l);
92237da2899SCharles.Forsyth 				corrupted(str, "chain hdr!=MAGIC_E", p, bc, v);
92337da2899SCharles.Forsyth 				goto nextpool;
92437da2899SCharles.Forsyth 			}
92537da2899SCharles.Forsyth 			ec = B2LIMIT(bc);
92637da2899SCharles.Forsyth 			if (((Bhdr*)v >= bc) && ((Bhdr*)v < ec))
92737da2899SCharles.Forsyth 				goto found;
92837da2899SCharles.Forsyth 		}
92937da2899SCharles.Forsyth 		unlock(&p->l);
93037da2899SCharles.Forsyth nextpool:	;
93137da2899SCharles.Forsyth 	}
93237da2899SCharles.Forsyth 	print("%s: %p not in pools\n", str, v);
93337da2899SCharles.Forsyth 	return;
93437da2899SCharles.Forsyth 
93537da2899SCharles.Forsyth found:
93637da2899SCharles.Forsyth 	for (b = bc; b < ec; b = nb) {
93737da2899SCharles.Forsyth 		switch(b->magic) {
93837da2899SCharles.Forsyth 		case MAGIC_F:
93937da2899SCharles.Forsyth 			msg = "free blk";
94037da2899SCharles.Forsyth 			break;
94137da2899SCharles.Forsyth 		case MAGIC_I:
94237da2899SCharles.Forsyth 			msg = "immutable block";
94337da2899SCharles.Forsyth 			break;
94437da2899SCharles.Forsyth 		case MAGIC_A:
94537da2899SCharles.Forsyth 			msg = "block";
94637da2899SCharles.Forsyth 			break;
94737da2899SCharles.Forsyth 		default:
94837da2899SCharles.Forsyth 			if (b == bc && b->magic == MAGIC_E) {
94937da2899SCharles.Forsyth 				msg = "pool hdr";
95037da2899SCharles.Forsyth 				break;
95137da2899SCharles.Forsyth 			}
95237da2899SCharles.Forsyth 			unlock(&p->l);
95337da2899SCharles.Forsyth 			corrupted(str, "bad magic", p, b, v);
95437da2899SCharles.Forsyth 			goto badchunk;
95537da2899SCharles.Forsyth 		}
95637da2899SCharles.Forsyth 		if (b->size <= 0 || (b->size & p->quanta)) {
95737da2899SCharles.Forsyth 			unlock(&p->l);
95837da2899SCharles.Forsyth 			corrupted(str, "bad size", p, b, v);
95937da2899SCharles.Forsyth 			goto badchunk;
96037da2899SCharles.Forsyth 		}
96137da2899SCharles.Forsyth 		if (fb != nil)
96237da2899SCharles.Forsyth 			break;
96337da2899SCharles.Forsyth 		nb = B2NB(b);
96437da2899SCharles.Forsyth 		if ((Bhdr*)v < nb) {
96537da2899SCharles.Forsyth 			fb = b;
96637da2899SCharles.Forsyth 			fsz = b->size;
96737da2899SCharles.Forsyth 			fmsg = msg;
96837da2899SCharles.Forsyth 		}
96937da2899SCharles.Forsyth 	}
97037da2899SCharles.Forsyth 	unlock(&p->l);
97137da2899SCharles.Forsyth 	if (b >= ec) {
97237da2899SCharles.Forsyth 		if (b > ec)
97337da2899SCharles.Forsyth 			corrupted(str, "chain size mismatch", p, b, v);
97437da2899SCharles.Forsyth 		else if (b->magic != MAGIC_E)
97537da2899SCharles.Forsyth 			corrupted(str, "chain end!=MAGIC_E", p, b, v);
97637da2899SCharles.Forsyth 	}
97737da2899SCharles.Forsyth badchunk:
97837da2899SCharles.Forsyth 	if (fb != nil) {
97937da2899SCharles.Forsyth 		print("%s: %p in %s:", str, v, p->name);
98037da2899SCharles.Forsyth 		if (fb == v)
98137da2899SCharles.Forsyth 			print(" is %s '%lux\n", fmsg, fsz);
98237da2899SCharles.Forsyth 		else
98337da2899SCharles.Forsyth 			print(" in %s at %p'%lux\n", fmsg, fb, fsz);
98437da2899SCharles.Forsyth 		dumpvl("area", (ulong *)((ulong)v & ~3)-4, 20);
98537da2899SCharles.Forsyth 	}
98637da2899SCharles.Forsyth }
98737da2899SCharles.Forsyth 
98837da2899SCharles.Forsyth char *
poolaudit(char * (* audit)(int,Bhdr *))98937da2899SCharles.Forsyth poolaudit(char*(*audit)(int, Bhdr *))
99037da2899SCharles.Forsyth {
99137da2899SCharles.Forsyth 	Pool *p;
99237da2899SCharles.Forsyth 	Bhdr *bc, *ec, *b;
99337da2899SCharles.Forsyth 	char *r = nil;
99437da2899SCharles.Forsyth 
99537da2899SCharles.Forsyth 	for (p = &table.pool[0]; p < &table.pool[nelem(table.pool)]; p++) {
99637da2899SCharles.Forsyth 		lock(&p->l);
99737da2899SCharles.Forsyth 		for (bc = p->chain; bc != nil; bc = bc->clink) {
99837da2899SCharles.Forsyth 			if (bc->magic != MAGIC_E) {
99937da2899SCharles.Forsyth 				unlock(&p->l);
100037da2899SCharles.Forsyth 				return "bad chain hdr";
100137da2899SCharles.Forsyth 			}
100237da2899SCharles.Forsyth 			ec = B2LIMIT(bc);
100337da2899SCharles.Forsyth 			for (b = bc; b < ec; b = B2NB(b)) {
100437da2899SCharles.Forsyth 				if (b->size <= 0 || (b->size & p->quanta))
100537da2899SCharles.Forsyth 					r = "bad size in bhdr";
100637da2899SCharles.Forsyth 				else
100737da2899SCharles.Forsyth 					switch(b->magic) {
100837da2899SCharles.Forsyth 					case MAGIC_E:
100937da2899SCharles.Forsyth 						if (b != bc) {
101037da2899SCharles.Forsyth 							r = "unexpected MAGIC_E";
101137da2899SCharles.Forsyth 							break;
101237da2899SCharles.Forsyth 						}
101337da2899SCharles.Forsyth 					case MAGIC_F:
101437da2899SCharles.Forsyth 					case MAGIC_A:
101537da2899SCharles.Forsyth 					case MAGIC_I:
101637da2899SCharles.Forsyth 						r = audit(p->pnum, b);
101737da2899SCharles.Forsyth 						break;
101837da2899SCharles.Forsyth 					default:
101937da2899SCharles.Forsyth 						r = "bad magic";
102037da2899SCharles.Forsyth 					}
102137da2899SCharles.Forsyth 				if (r != nil) {
102237da2899SCharles.Forsyth 					unlock(&p->l);
102337da2899SCharles.Forsyth 					return r;
102437da2899SCharles.Forsyth 				}
102537da2899SCharles.Forsyth 			}
102637da2899SCharles.Forsyth 			if (b != ec || b->magic != MAGIC_E) {
102737da2899SCharles.Forsyth 				unlock(&p->l);
102837da2899SCharles.Forsyth 				return "bad chain ending";
102937da2899SCharles.Forsyth 			}
103037da2899SCharles.Forsyth 		}
103137da2899SCharles.Forsyth 		unlock(&p->l);
103237da2899SCharles.Forsyth 	}
103337da2899SCharles.Forsyth 	return r;
103437da2899SCharles.Forsyth }
1035