xref: /plan9-contrib/sys/src/9/port/xalloc.c (revision 9d1c8c20e8d04c7372f3e406dd22c2a0a814a1fa)
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 #define datoff		((ulong)((Xhdr*)0)->data)
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier enum
107dd7cddfSDavid du Colombier {
117dd7cddfSDavid du Colombier 	Chunk		= 64*1024,
127dd7cddfSDavid du Colombier 	Nhole		= 128,
137dd7cddfSDavid du Colombier 	Magichole	= 0x484F4C45,			/* HOLE */
147dd7cddfSDavid du Colombier };
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier typedef struct Hole Hole;
177dd7cddfSDavid du Colombier typedef struct Xalloc Xalloc;
187dd7cddfSDavid du Colombier typedef struct Xhdr Xhdr;
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier struct Hole
217dd7cddfSDavid du Colombier {
227dd7cddfSDavid du Colombier 	ulong	addr;
237dd7cddfSDavid du Colombier 	ulong	size;
247dd7cddfSDavid du Colombier 	ulong	top;
257dd7cddfSDavid du Colombier 	Hole*	link;
267dd7cddfSDavid du Colombier };
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier struct Xhdr
297dd7cddfSDavid du Colombier {
307dd7cddfSDavid du Colombier 	ulong	size;
317dd7cddfSDavid du Colombier 	ulong	magix;
327dd7cddfSDavid du Colombier 	char	data[1];
337dd7cddfSDavid du Colombier };
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier struct Xalloc
367dd7cddfSDavid du Colombier {
377dd7cddfSDavid du Colombier 	Lock;
387dd7cddfSDavid du Colombier 	Hole	hole[Nhole];
397dd7cddfSDavid du Colombier 	Hole*	flist;
407dd7cddfSDavid du Colombier 	Hole*	table;
417dd7cddfSDavid du Colombier };
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier static Xalloc	xlists;
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier void
467dd7cddfSDavid du Colombier xinit(void)
477dd7cddfSDavid du Colombier {
487dd7cddfSDavid du Colombier 	Hole *h, *eh;
497dd7cddfSDavid du Colombier 	int upages, np0, np1;
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;
587dd7cddfSDavid du Colombier 	np1 = upages;
597dd7cddfSDavid du Colombier 	if(np1 > conf.npage1)
607dd7cddfSDavid du Colombier 		np1 = conf.npage1;
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier 	palloc.p1 = conf.base1 + (conf.npage1 - np1)*BY2PG;
637dd7cddfSDavid du Colombier 	conf.npage1 -= np1;
647dd7cddfSDavid du Colombier 	xhole(conf.base1, conf.npage1*BY2PG);
657dd7cddfSDavid du Colombier 	conf.npage1 = conf.base1+(conf.npage1*BY2PG);
667dd7cddfSDavid du Colombier 	upages -= np1;
677dd7cddfSDavid du Colombier 
687dd7cddfSDavid du Colombier 	np0 = upages;
697dd7cddfSDavid du Colombier 	if(np0 > conf.npage0)
707dd7cddfSDavid du Colombier 		np0 = conf.npage0;
717dd7cddfSDavid du Colombier 
727dd7cddfSDavid du Colombier 	palloc.p0 = conf.base0 + (conf.npage0 - np0)*BY2PG;
737dd7cddfSDavid du Colombier 	conf.npage0 -= np0;
747dd7cddfSDavid du Colombier 	xhole(conf.base0, conf.npage0*BY2PG);
757dd7cddfSDavid du Colombier 	conf.npage0 = conf.base0+(conf.npage0*BY2PG);
767dd7cddfSDavid du Colombier 
777dd7cddfSDavid du Colombier 	palloc.np0 = np0;
787dd7cddfSDavid du Colombier 	palloc.np1 = np1;
797dd7cddfSDavid du Colombier 	/* Save the bounds of kernel alloc memory for kernel mmu mapping */
807dd7cddfSDavid du Colombier 	conf.base0 = (ulong)KADDR(conf.base0);
817dd7cddfSDavid du Colombier 	conf.base1 = (ulong)KADDR(conf.base1);
827dd7cddfSDavid du Colombier 	conf.npage0 = (ulong)KADDR(conf.npage0);
837dd7cddfSDavid du Colombier 	conf.npage1 = (ulong)KADDR(conf.npage1);
847dd7cddfSDavid du Colombier }
857dd7cddfSDavid du Colombier 
867dd7cddfSDavid du Colombier void*
877dd7cddfSDavid du Colombier xspanalloc(ulong size, int align, ulong span)
887dd7cddfSDavid du Colombier {
897dd7cddfSDavid du Colombier 	ulong a, v, t;
907dd7cddfSDavid du Colombier 	a = (ulong)xalloc(size+align+span);
917dd7cddfSDavid du Colombier 	if(a == 0)
929a747e4fSDavid du Colombier 		panic("xspanalloc: %lud %d %lux\n", size, align, span);
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier 	if(span > 2) {
957dd7cddfSDavid du Colombier 		v = (a + span) & ~(span-1);
967dd7cddfSDavid du Colombier 		t = v - a;
977dd7cddfSDavid du Colombier 		if(t > 0)
987dd7cddfSDavid du Colombier 			xhole(PADDR(a), t);
997dd7cddfSDavid du Colombier 		t = a + span - v;
1007dd7cddfSDavid du Colombier 		if(t > 0)
1017dd7cddfSDavid du Colombier 			xhole(PADDR(v+size+align), t);
1027dd7cddfSDavid du Colombier 	}
1037dd7cddfSDavid du Colombier 	else
1047dd7cddfSDavid du Colombier 		v = a;
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier 	if(align > 1)
1077dd7cddfSDavid du Colombier 		v = (v + align) & ~(align-1);
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier 	return (void*)v;
1107dd7cddfSDavid du Colombier }
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier void*
1137dd7cddfSDavid du Colombier xallocz(ulong size, int zero)
1147dd7cddfSDavid du Colombier {
1157dd7cddfSDavid du Colombier 	Xhdr *p;
1167dd7cddfSDavid du Colombier 	Hole *h, **l;
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 	size += BY2V + sizeof(Xhdr);
1197dd7cddfSDavid du Colombier 	size &= ~(BY2V-1);
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 	ilock(&xlists);
1227dd7cddfSDavid du Colombier 	l = &xlists.table;
1237dd7cddfSDavid du Colombier 	for(h = *l; h; h = h->link) {
1247dd7cddfSDavid du Colombier 		if(h->size >= size) {
1257dd7cddfSDavid du Colombier 			p = (Xhdr*)h->addr;
1267dd7cddfSDavid du Colombier 			h->addr += size;
1277dd7cddfSDavid du Colombier 			h->size -= size;
1287dd7cddfSDavid du Colombier 			if(h->size == 0) {
1297dd7cddfSDavid du Colombier 				*l = h->link;
1307dd7cddfSDavid du Colombier 				h->link = xlists.flist;
1317dd7cddfSDavid du Colombier 				xlists.flist = h;
1327dd7cddfSDavid du Colombier 			}
1337dd7cddfSDavid du Colombier 			iunlock(&xlists);
1347dd7cddfSDavid du Colombier 			p = KADDR(p);
1357dd7cddfSDavid du Colombier 			if(zero)
1367dd7cddfSDavid du Colombier 				memset(p->data, 0, size);
137*9d1c8c20SDavid du Colombier 			p->magix = Magichole;
138*9d1c8c20SDavid du Colombier 			p->size = size;
1397dd7cddfSDavid du Colombier 			return p->data;
1407dd7cddfSDavid du Colombier 		}
1417dd7cddfSDavid du Colombier 		l = &h->link;
1427dd7cddfSDavid du Colombier 	}
1437dd7cddfSDavid du Colombier 	iunlock(&xlists);
1447dd7cddfSDavid du Colombier 	return nil;
1457dd7cddfSDavid du Colombier }
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier void*
1487dd7cddfSDavid du Colombier xalloc(ulong size)
1497dd7cddfSDavid du Colombier {
1507dd7cddfSDavid du Colombier 	return xallocz(size, 1);
1517dd7cddfSDavid du Colombier }
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier void
1547dd7cddfSDavid du Colombier xfree(void *p)
1557dd7cddfSDavid du Colombier {
1567dd7cddfSDavid du Colombier 	Xhdr *x;
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier 	x = (Xhdr*)((ulong)p - datoff);
1597dd7cddfSDavid du Colombier 	if(x->magix != Magichole) {
1607dd7cddfSDavid du Colombier 		xsummary();
1619a747e4fSDavid du Colombier 		panic("xfree(0x%lux) 0x%lux!=0x%lux", p, (ulong)Magichole, x->magix);
1627dd7cddfSDavid du Colombier 	}
1637dd7cddfSDavid du Colombier 	xhole(PADDR(x), x->size);
1647dd7cddfSDavid du Colombier }
1657dd7cddfSDavid du Colombier 
1667dd7cddfSDavid du Colombier int
1677dd7cddfSDavid du Colombier xmerge(void *vp, void *vq)
1687dd7cddfSDavid du Colombier {
1697dd7cddfSDavid du Colombier 	Xhdr *p, *q;
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	p = vp;
1727dd7cddfSDavid du Colombier 	if((uchar*)vp+p->size == (uchar*)vq) {
1737dd7cddfSDavid du Colombier 		q = vq;
1747dd7cddfSDavid du Colombier 		p->size += q->size;
1757dd7cddfSDavid du Colombier 		return 1;
1767dd7cddfSDavid du Colombier 	}
1777dd7cddfSDavid du Colombier 	return 0;
1787dd7cddfSDavid du Colombier }
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier void
1817dd7cddfSDavid du Colombier xhole(ulong addr, ulong size)
1827dd7cddfSDavid du Colombier {
1837dd7cddfSDavid du Colombier 	ulong top;
1847dd7cddfSDavid du Colombier 	Hole *h, *c, **l;
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier 	if(size == 0)
1877dd7cddfSDavid du Colombier 		return;
1887dd7cddfSDavid du Colombier 
1897dd7cddfSDavid du Colombier 	top = addr + size;
1907dd7cddfSDavid du Colombier 	ilock(&xlists);
1917dd7cddfSDavid du Colombier 	l = &xlists.table;
1927dd7cddfSDavid du Colombier 	for(h = *l; h; h = h->link) {
1937dd7cddfSDavid du Colombier 		if(h->top == addr) {
1947dd7cddfSDavid du Colombier 			h->size += size;
1957dd7cddfSDavid du Colombier 			h->top = h->addr+h->size;
1967dd7cddfSDavid du Colombier 			c = h->link;
1977dd7cddfSDavid du Colombier 			if(c && h->top == c->addr) {
1987dd7cddfSDavid du Colombier 				h->top += c->size;
1997dd7cddfSDavid du Colombier 				h->size += c->size;
2007dd7cddfSDavid du Colombier 				h->link = c->link;
2017dd7cddfSDavid du Colombier 				c->link = xlists.flist;
2027dd7cddfSDavid du Colombier 				xlists.flist = c;
2037dd7cddfSDavid du Colombier 			}
2047dd7cddfSDavid du Colombier 			iunlock(&xlists);
2057dd7cddfSDavid du Colombier 			return;
2067dd7cddfSDavid du Colombier 		}
2077dd7cddfSDavid du Colombier 		if(h->addr > addr)
2087dd7cddfSDavid du Colombier 			break;
2097dd7cddfSDavid du Colombier 		l = &h->link;
2107dd7cddfSDavid du Colombier 	}
2117dd7cddfSDavid du Colombier 	if(h && top == h->addr) {
2127dd7cddfSDavid du Colombier 		h->addr -= size;
2137dd7cddfSDavid du Colombier 		h->size += size;
2147dd7cddfSDavid du Colombier 		iunlock(&xlists);
2157dd7cddfSDavid du Colombier 		return;
2167dd7cddfSDavid du Colombier 	}
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier 	if(xlists.flist == nil) {
2197dd7cddfSDavid du Colombier 		iunlock(&xlists);
2207dd7cddfSDavid du Colombier 		print("xfree: no free holes, leaked %lud bytes\n", size);
2217dd7cddfSDavid du Colombier 		return;
2227dd7cddfSDavid du Colombier 	}
2237dd7cddfSDavid du Colombier 
2247dd7cddfSDavid du Colombier 	h = xlists.flist;
2257dd7cddfSDavid du Colombier 	xlists.flist = h->link;
2267dd7cddfSDavid du Colombier 	h->addr = addr;
2277dd7cddfSDavid du Colombier 	h->top = top;
2287dd7cddfSDavid du Colombier 	h->size = size;
2297dd7cddfSDavid du Colombier 	h->link = *l;
2307dd7cddfSDavid du Colombier 	*l = h;
2317dd7cddfSDavid du Colombier 	iunlock(&xlists);
2327dd7cddfSDavid du Colombier }
2337dd7cddfSDavid du Colombier 
2347dd7cddfSDavid du Colombier void
2357dd7cddfSDavid du Colombier xsummary(void)
2367dd7cddfSDavid du Colombier {
2377dd7cddfSDavid du Colombier 	int i;
2387dd7cddfSDavid du Colombier 	Hole *h;
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier 	i = 0;
2417dd7cddfSDavid du Colombier 	for(h = xlists.flist; h; h = h->link)
2427dd7cddfSDavid du Colombier 		i++;
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier 	print("%d holes free\n", i);
2457dd7cddfSDavid du Colombier 	i = 0;
2467dd7cddfSDavid du Colombier 	for(h = xlists.table; h; h = h->link) {
2477dd7cddfSDavid du Colombier 		print("%.8lux %.8lux %lud\n", h->addr, h->top, h->size);
2487dd7cddfSDavid du Colombier 		i += h->size;
2497dd7cddfSDavid du Colombier 	}
2507dd7cddfSDavid du Colombier 	print("%d bytes free\n", i);
2517dd7cddfSDavid du Colombier }
252