xref: /plan9/sys/src/9/port/xalloc.c (revision a20d0e67a42ae3426019dcedb4197f7bded7a5ed)
17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier enum
87dd7cddfSDavid du Colombier {
97dd7cddfSDavid du Colombier 	Nhole		= 128,
107dd7cddfSDavid du Colombier 	Magichole	= 0x484F4C45,			/* HOLE */
117dd7cddfSDavid du Colombier };
127dd7cddfSDavid du Colombier 
137dd7cddfSDavid du Colombier typedef struct Hole Hole;
147dd7cddfSDavid du Colombier typedef struct Xalloc Xalloc;
157dd7cddfSDavid du Colombier typedef struct Xhdr Xhdr;
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier struct Hole
187dd7cddfSDavid du Colombier {
197dd7cddfSDavid du Colombier 	ulong	addr;
207dd7cddfSDavid du Colombier 	ulong	size;
217dd7cddfSDavid du Colombier 	ulong	top;
227dd7cddfSDavid du Colombier 	Hole*	link;
237dd7cddfSDavid du Colombier };
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier struct Xhdr
267dd7cddfSDavid du Colombier {
277dd7cddfSDavid du Colombier 	ulong	size;
287dd7cddfSDavid du Colombier 	ulong	magix;
291072dfd1SDavid du Colombier 	char	data[];
307dd7cddfSDavid du Colombier };
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier struct Xalloc
337dd7cddfSDavid du Colombier {
347dd7cddfSDavid du Colombier 	Lock;
357dd7cddfSDavid du Colombier 	Hole	hole[Nhole];
367dd7cddfSDavid du Colombier 	Hole*	flist;
377dd7cddfSDavid du Colombier 	Hole*	table;
387dd7cddfSDavid du Colombier };
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier static Xalloc	xlists;
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier void
xinit(void)437dd7cddfSDavid du Colombier xinit(void)
447dd7cddfSDavid du Colombier {
454de34a7eSDavid du Colombier 	int i, n, upages, kpages;
46c717cbbdSDavid du Colombier 	ulong maxpages;
474de34a7eSDavid du Colombier 	Confmem *m;
484de34a7eSDavid du Colombier 	Pallocmem *pm;
497dd7cddfSDavid du Colombier 	Hole *h, *eh;
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier 	eh = &xlists.hole[Nhole-1];
527dd7cddfSDavid du Colombier 	for(h = xlists.hole; h < eh; h++)
537dd7cddfSDavid du Colombier 		h->link = h+1;
547dd7cddfSDavid du Colombier 
557dd7cddfSDavid du Colombier 	xlists.flist = xlists.hole;
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier 	upages = conf.upages;
584de34a7eSDavid du Colombier 	kpages = conf.npage - upages;
594de34a7eSDavid du Colombier 	pm = palloc.mem;
604de34a7eSDavid du Colombier 	for(i=0; i<nelem(conf.mem); i++){
614de34a7eSDavid du Colombier 		m = &conf.mem[i];
624de34a7eSDavid du Colombier 		n = m->npage;
634de34a7eSDavid du Colombier 		if(n > kpages)
644de34a7eSDavid du Colombier 			n = kpages;
65c717cbbdSDavid du Colombier 		/* don't try to use non-KADDR-able memory for kernel */
66c717cbbdSDavid du Colombier 		maxpages = cankaddr(m->base)/BY2PG;
67c717cbbdSDavid du Colombier 		if(n > maxpages)
68c717cbbdSDavid du Colombier 			n = maxpages;
694de34a7eSDavid du Colombier 		/* first give to kernel */
704de34a7eSDavid du Colombier 		if(n > 0){
714de34a7eSDavid du Colombier 			m->kbase = (ulong)KADDR(m->base);
724de34a7eSDavid du Colombier 			m->klimit = (ulong)KADDR(m->base+n*BY2PG);
734de34a7eSDavid du Colombier 			xhole(m->base, n*BY2PG);
744de34a7eSDavid du Colombier 			kpages -= n;
754de34a7eSDavid du Colombier 		}
764de34a7eSDavid du Colombier 		/* if anything left over, give to user */
774de34a7eSDavid du Colombier 		if(n < m->npage){
784de34a7eSDavid du Colombier 			if(pm >= palloc.mem+nelem(palloc.mem)){
794de34a7eSDavid du Colombier 				print("xinit: losing %lud pages\n", m->npage-n);
804de34a7eSDavid du Colombier 				continue;
814de34a7eSDavid du Colombier 			}
824de34a7eSDavid du Colombier 			pm->base = m->base+n*BY2PG;
834de34a7eSDavid du Colombier 			pm->npage = m->npage - n;
844de34a7eSDavid du Colombier 			pm++;
854de34a7eSDavid du Colombier 		}
864de34a7eSDavid du Colombier 	}
872210c76eSDavid du Colombier //	xsummary();			/* call it from main if desired */
887dd7cddfSDavid du Colombier }
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier void*
xspanalloc(ulong size,int align,ulong span)917dd7cddfSDavid du Colombier xspanalloc(ulong size, int align, ulong span)
927dd7cddfSDavid du Colombier {
937dd7cddfSDavid du Colombier 	ulong a, v, t;
947dd7cddfSDavid du Colombier 	a = (ulong)xalloc(size+align+span);
957dd7cddfSDavid du Colombier 	if(a == 0)
9693631029SDavid du Colombier 		panic("xspanalloc: %lud %d %lux", size, align, span);
977dd7cddfSDavid du Colombier 
987dd7cddfSDavid du Colombier 	if(span > 2) {
997dd7cddfSDavid du Colombier 		v = (a + span) & ~(span-1);
1007dd7cddfSDavid du Colombier 		t = v - a;
1017dd7cddfSDavid du Colombier 		if(t > 0)
1027dd7cddfSDavid du Colombier 			xhole(PADDR(a), t);
1037dd7cddfSDavid du Colombier 		t = a + span - v;
1047dd7cddfSDavid du Colombier 		if(t > 0)
1057dd7cddfSDavid du Colombier 			xhole(PADDR(v+size+align), t);
1067dd7cddfSDavid du Colombier 	}
1077dd7cddfSDavid du Colombier 	else
1087dd7cddfSDavid du Colombier 		v = a;
1097dd7cddfSDavid du Colombier 
1107dd7cddfSDavid du Colombier 	if(align > 1)
1117dd7cddfSDavid du Colombier 		v = (v + align) & ~(align-1);
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier 	return (void*)v;
1147dd7cddfSDavid du Colombier }
1157dd7cddfSDavid du Colombier 
1167dd7cddfSDavid du Colombier void*
xallocz(ulong size,int zero)1177dd7cddfSDavid du Colombier xallocz(ulong size, int zero)
1187dd7cddfSDavid du Colombier {
1197dd7cddfSDavid du Colombier 	Xhdr *p;
1207dd7cddfSDavid du Colombier 	Hole *h, **l;
1217dd7cddfSDavid du Colombier 
122410ea80bSDavid du Colombier 	/* add room for magix & size overhead, round up to nearest vlong */
1231072dfd1SDavid du Colombier 	size += BY2V + offsetof(Xhdr, data[0]);
1247dd7cddfSDavid du Colombier 	size &= ~(BY2V-1);
1257dd7cddfSDavid du Colombier 
1267dd7cddfSDavid du Colombier 	ilock(&xlists);
1277dd7cddfSDavid du Colombier 	l = &xlists.table;
1287dd7cddfSDavid du Colombier 	for(h = *l; h; h = h->link) {
1297dd7cddfSDavid du Colombier 		if(h->size >= size) {
1304de34a7eSDavid du Colombier 			p = (Xhdr*)KADDR(h->addr);
1317dd7cddfSDavid du Colombier 			h->addr += size;
1327dd7cddfSDavid du Colombier 			h->size -= size;
1337dd7cddfSDavid du Colombier 			if(h->size == 0) {
1347dd7cddfSDavid du Colombier 				*l = h->link;
1357dd7cddfSDavid du Colombier 				h->link = xlists.flist;
1367dd7cddfSDavid du Colombier 				xlists.flist = h;
1377dd7cddfSDavid du Colombier 			}
1387dd7cddfSDavid du Colombier 			iunlock(&xlists);
1397dd7cddfSDavid du Colombier 			if(zero)
140410ea80bSDavid du Colombier 				memset(p, 0, size);
1419d1c8c20SDavid du Colombier 			p->magix = Magichole;
1429d1c8c20SDavid du Colombier 			p->size = size;
1437dd7cddfSDavid du Colombier 			return p->data;
1447dd7cddfSDavid du Colombier 		}
1457dd7cddfSDavid du Colombier 		l = &h->link;
1467dd7cddfSDavid du Colombier 	}
1477dd7cddfSDavid du Colombier 	iunlock(&xlists);
1487dd7cddfSDavid du Colombier 	return nil;
1497dd7cddfSDavid du Colombier }
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier void*
xalloc(ulong size)1527dd7cddfSDavid du Colombier xalloc(ulong size)
1537dd7cddfSDavid du Colombier {
1547dd7cddfSDavid du Colombier 	return xallocz(size, 1);
1557dd7cddfSDavid du Colombier }
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier void
xfree(void * p)1587dd7cddfSDavid du Colombier xfree(void *p)
1597dd7cddfSDavid du Colombier {
1607dd7cddfSDavid du Colombier 	Xhdr *x;
1617dd7cddfSDavid du Colombier 
1621072dfd1SDavid du Colombier 	x = (Xhdr*)((ulong)p - offsetof(Xhdr, data[0]));
1637dd7cddfSDavid du Colombier 	if(x->magix != Magichole) {
1647dd7cddfSDavid du Colombier 		xsummary();
1651072dfd1SDavid du Colombier 		panic("xfree(%#p) %#ux != %#lux", p, Magichole, x->magix);
1667dd7cddfSDavid du Colombier 	}
167c717cbbdSDavid du Colombier 	xhole(PADDR((uintptr)x), x->size);
1687dd7cddfSDavid du Colombier }
1697dd7cddfSDavid du Colombier 
1707dd7cddfSDavid du Colombier int
xmerge(void * vp,void * vq)1717dd7cddfSDavid du Colombier xmerge(void *vp, void *vq)
1727dd7cddfSDavid du Colombier {
1737dd7cddfSDavid du Colombier 	Xhdr *p, *q;
1747dd7cddfSDavid du Colombier 
1751072dfd1SDavid du Colombier 	p = (Xhdr*)(((ulong)vp - offsetof(Xhdr, data[0])));
1761072dfd1SDavid du Colombier 	q = (Xhdr*)(((ulong)vq - offsetof(Xhdr, data[0])));
1771072dfd1SDavid du Colombier 	if(p->magix != Magichole || q->magix != Magichole) {
178410ea80bSDavid du Colombier 		int i;
179410ea80bSDavid du Colombier 		ulong *wd;
180410ea80bSDavid du Colombier 		void *badp;
181410ea80bSDavid du Colombier 
1821072dfd1SDavid du Colombier 		xsummary();
183410ea80bSDavid du Colombier 		badp = (p->magix != Magichole? p: q);
184410ea80bSDavid du Colombier 		wd = (ulong *)badp - 12;
185410ea80bSDavid du Colombier 		for (i = 24; i-- > 0; ) {
186410ea80bSDavid du Colombier 			print("%#p: %lux", wd, *wd);
187410ea80bSDavid du Colombier 			if (wd == badp)
188410ea80bSDavid du Colombier 				print(" <-");
189410ea80bSDavid du Colombier 			print("\n");
190410ea80bSDavid du Colombier 			wd++;
191410ea80bSDavid du Colombier 		}
19293631029SDavid du Colombier 		panic("xmerge(%#p, %#p) bad magic %#lux, %#lux",
1931072dfd1SDavid du Colombier 			vp, vq, p->magix, q->magix);
1941072dfd1SDavid du Colombier 	}
1951072dfd1SDavid du Colombier 	if((uchar*)p+p->size == (uchar*)q) {
1967dd7cddfSDavid du Colombier 		p->size += q->size;
1977dd7cddfSDavid du Colombier 		return 1;
1987dd7cddfSDavid du Colombier 	}
1997dd7cddfSDavid du Colombier 	return 0;
2007dd7cddfSDavid du Colombier }
2017dd7cddfSDavid du Colombier 
2027dd7cddfSDavid du Colombier void
xhole(ulong addr,ulong size)2037dd7cddfSDavid du Colombier xhole(ulong addr, ulong size)
2047dd7cddfSDavid du Colombier {
2057dd7cddfSDavid du Colombier 	ulong top;
2067dd7cddfSDavid du Colombier 	Hole *h, *c, **l;
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 	if(size == 0)
2097dd7cddfSDavid du Colombier 		return;
2107dd7cddfSDavid du Colombier 
2117dd7cddfSDavid du Colombier 	top = addr + size;
2127dd7cddfSDavid du Colombier 	ilock(&xlists);
2137dd7cddfSDavid du Colombier 	l = &xlists.table;
2147dd7cddfSDavid du Colombier 	for(h = *l; h; h = h->link) {
2157dd7cddfSDavid du Colombier 		if(h->top == addr) {
2167dd7cddfSDavid du Colombier 			h->size += size;
2177dd7cddfSDavid du Colombier 			h->top = h->addr+h->size;
2187dd7cddfSDavid du Colombier 			c = h->link;
2197dd7cddfSDavid du Colombier 			if(c && h->top == c->addr) {
2207dd7cddfSDavid du Colombier 				h->top += c->size;
2217dd7cddfSDavid du Colombier 				h->size += c->size;
2227dd7cddfSDavid du Colombier 				h->link = c->link;
2237dd7cddfSDavid du Colombier 				c->link = xlists.flist;
2247dd7cddfSDavid du Colombier 				xlists.flist = c;
2257dd7cddfSDavid du Colombier 			}
2267dd7cddfSDavid du Colombier 			iunlock(&xlists);
2277dd7cddfSDavid du Colombier 			return;
2287dd7cddfSDavid du Colombier 		}
2297dd7cddfSDavid du Colombier 		if(h->addr > addr)
2307dd7cddfSDavid du Colombier 			break;
2317dd7cddfSDavid du Colombier 		l = &h->link;
2327dd7cddfSDavid du Colombier 	}
2337dd7cddfSDavid du Colombier 	if(h && top == h->addr) {
2347dd7cddfSDavid du Colombier 		h->addr -= size;
2357dd7cddfSDavid du Colombier 		h->size += size;
2367dd7cddfSDavid du Colombier 		iunlock(&xlists);
2377dd7cddfSDavid du Colombier 		return;
2387dd7cddfSDavid du Colombier 	}
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier 	if(xlists.flist == nil) {
2417dd7cddfSDavid du Colombier 		iunlock(&xlists);
2427dd7cddfSDavid du Colombier 		print("xfree: no free holes, leaked %lud bytes\n", size);
2437dd7cddfSDavid du Colombier 		return;
2447dd7cddfSDavid du Colombier 	}
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier 	h = xlists.flist;
2477dd7cddfSDavid du Colombier 	xlists.flist = h->link;
2487dd7cddfSDavid du Colombier 	h->addr = addr;
2497dd7cddfSDavid du Colombier 	h->top = top;
2507dd7cddfSDavid du Colombier 	h->size = size;
2517dd7cddfSDavid du Colombier 	h->link = *l;
2527dd7cddfSDavid du Colombier 	*l = h;
2537dd7cddfSDavid du Colombier 	iunlock(&xlists);
2547dd7cddfSDavid du Colombier }
2557dd7cddfSDavid du Colombier 
2567dd7cddfSDavid du Colombier void
xsummary(void)2577dd7cddfSDavid du Colombier xsummary(void)
2587dd7cddfSDavid du Colombier {
2597dd7cddfSDavid du Colombier 	int i;
2607dd7cddfSDavid du Colombier 	Hole *h;
2617dd7cddfSDavid du Colombier 
2627dd7cddfSDavid du Colombier 	i = 0;
2637dd7cddfSDavid du Colombier 	for(h = xlists.flist; h; h = h->link)
2647dd7cddfSDavid du Colombier 		i++;
2657dd7cddfSDavid du Colombier 
266*a20d0e67SDavid du Colombier 	print("%d holes free", i);
2677dd7cddfSDavid du Colombier 	i = 0;
2687dd7cddfSDavid du Colombier 	for(h = xlists.table; h; h = h->link) {
269*a20d0e67SDavid du Colombier 		if (0) {
270*a20d0e67SDavid du Colombier 			print("addr %#.8lux top %#.8lux size %lud\n",
271*a20d0e67SDavid du Colombier 				h->addr, h->top, h->size);
272*a20d0e67SDavid du Colombier 			delay(10);
273*a20d0e67SDavid du Colombier 		}
2747dd7cddfSDavid du Colombier 		i += h->size;
275*a20d0e67SDavid du Colombier 		if (h == h->link) {
276*a20d0e67SDavid du Colombier 			print("xsummary: infinite loop broken\n");
277*a20d0e67SDavid du Colombier 			break;
278*a20d0e67SDavid du Colombier 		}
2797dd7cddfSDavid du Colombier 	}
2807dd7cddfSDavid du Colombier 	print(" %d bytes free\n", i);
2817dd7cddfSDavid du Colombier }
282