xref: /plan9/sys/src/9/port/xalloc.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 
7 enum
8 {
9 	Chunk		= 64*1024,
10 	Nhole		= 128,
11 	Magichole	= 0x484F4C45,			/* HOLE */
12 };
13 
14 typedef struct Hole Hole;
15 typedef struct Xalloc Xalloc;
16 typedef struct Xhdr Xhdr;
17 
18 struct Hole
19 {
20 	ulong	addr;
21 	ulong	size;
22 	ulong	top;
23 	Hole*	link;
24 };
25 
26 struct Xhdr
27 {
28 	ulong	size;
29 	ulong	magix;
30 	char	data[];
31 };
32 
33 struct Xalloc
34 {
35 	Lock;
36 	Hole	hole[Nhole];
37 	Hole*	flist;
38 	Hole*	table;
39 };
40 
41 static Xalloc	xlists;
42 
43 void
44 xinit(void)
45 {
46 	int i, n, upages, kpages;
47 	ulong maxpages;
48 	Confmem *m;
49 	Pallocmem *pm;
50 	Hole *h, *eh;
51 
52 	eh = &xlists.hole[Nhole-1];
53 	for(h = xlists.hole; h < eh; h++)
54 		h->link = h+1;
55 
56 	xlists.flist = xlists.hole;
57 
58 	upages = conf.upages;
59 	kpages = conf.npage - upages;
60 	pm = palloc.mem;
61 	for(i=0; i<nelem(conf.mem); i++){
62 		m = &conf.mem[i];
63 		n = m->npage;
64 		if(n > kpages)
65 			n = kpages;
66 		/* don't try to use non-KADDR-able memory for kernel */
67 		maxpages = cankaddr(m->base)/BY2PG;
68 		if(n > maxpages)
69 			n = maxpages;
70 		/* first give to kernel */
71 		if(n > 0){
72 			m->kbase = (ulong)KADDR(m->base);
73 			m->klimit = (ulong)KADDR(m->base+n*BY2PG);
74 			xhole(m->base, n*BY2PG);
75 			kpages -= n;
76 		}
77 		/* if anything left over, give to user */
78 		if(n < m->npage){
79 			if(pm >= palloc.mem+nelem(palloc.mem)){
80 				print("xinit: losing %lud pages\n", m->npage-n);
81 				continue;
82 			}
83 			pm->base = m->base+n*BY2PG;
84 			pm->npage = m->npage - n;
85 			pm++;
86 		}
87 	}
88 	xsummary();
89 }
90 
91 void*
92 xspanalloc(ulong size, int align, ulong span)
93 {
94 	ulong a, v, t;
95 	a = (ulong)xalloc(size+align+span);
96 	if(a == 0)
97 		panic("xspanalloc: %lud %d %lux\n", size, align, span);
98 
99 	if(span > 2) {
100 		v = (a + span) & ~(span-1);
101 		t = v - a;
102 		if(t > 0)
103 			xhole(PADDR(a), t);
104 		t = a + span - v;
105 		if(t > 0)
106 			xhole(PADDR(v+size+align), t);
107 	}
108 	else
109 		v = a;
110 
111 	if(align > 1)
112 		v = (v + align) & ~(align-1);
113 
114 	return (void*)v;
115 }
116 
117 void*
118 xallocz(ulong size, int zero)
119 {
120 	Xhdr *p;
121 	Hole *h, **l;
122 
123 	size += BY2V + offsetof(Xhdr, data[0]);
124 	size &= ~(BY2V-1);
125 
126 	ilock(&xlists);
127 	l = &xlists.table;
128 	for(h = *l; h; h = h->link) {
129 		if(h->size >= size) {
130 			p = (Xhdr*)KADDR(h->addr);
131 			h->addr += size;
132 			h->size -= size;
133 			if(h->size == 0) {
134 				*l = h->link;
135 				h->link = xlists.flist;
136 				xlists.flist = h;
137 			}
138 			iunlock(&xlists);
139 			if(zero)
140 				memset(p->data, 0, size);
141 			p->magix = Magichole;
142 			p->size = size;
143 			return p->data;
144 		}
145 		l = &h->link;
146 	}
147 	iunlock(&xlists);
148 	return nil;
149 }
150 
151 void*
152 xalloc(ulong size)
153 {
154 	return xallocz(size, 1);
155 }
156 
157 void
158 xfree(void *p)
159 {
160 	Xhdr *x;
161 
162 	x = (Xhdr*)((ulong)p - offsetof(Xhdr, data[0]));
163 	if(x->magix != Magichole) {
164 		xsummary();
165 		panic("xfree(%#p) %#ux != %#lux", p, Magichole, x->magix);
166 	}
167 	xhole(PADDR((uintptr)x), x->size);
168 }
169 
170 int
171 xmerge(void *vp, void *vq)
172 {
173 	Xhdr *p, *q;
174 
175 	p = (Xhdr*)(((ulong)vp - offsetof(Xhdr, data[0])));
176 	q = (Xhdr*)(((ulong)vq - offsetof(Xhdr, data[0])));
177 	if(p->magix != Magichole || q->magix != Magichole) {
178 		xsummary();
179 		panic("xmerge(%#p, %#p) bad magic %#lux, %#lux\n",
180 			vp, vq, p->magix, q->magix);
181 	}
182 	if((uchar*)p+p->size == (uchar*)q) {
183 		p->size += q->size;
184 		return 1;
185 	}
186 	return 0;
187 }
188 
189 void
190 xhole(ulong addr, ulong size)
191 {
192 	ulong top;
193 	Hole *h, *c, **l;
194 
195 	if(size == 0)
196 		return;
197 
198 	top = addr + size;
199 	ilock(&xlists);
200 	l = &xlists.table;
201 	for(h = *l; h; h = h->link) {
202 		if(h->top == addr) {
203 			h->size += size;
204 			h->top = h->addr+h->size;
205 			c = h->link;
206 			if(c && h->top == c->addr) {
207 				h->top += c->size;
208 				h->size += c->size;
209 				h->link = c->link;
210 				c->link = xlists.flist;
211 				xlists.flist = c;
212 			}
213 			iunlock(&xlists);
214 			return;
215 		}
216 		if(h->addr > addr)
217 			break;
218 		l = &h->link;
219 	}
220 	if(h && top == h->addr) {
221 		h->addr -= size;
222 		h->size += size;
223 		iunlock(&xlists);
224 		return;
225 	}
226 
227 	if(xlists.flist == nil) {
228 		iunlock(&xlists);
229 		print("xfree: no free holes, leaked %lud bytes\n", size);
230 		return;
231 	}
232 
233 	h = xlists.flist;
234 	xlists.flist = h->link;
235 	h->addr = addr;
236 	h->top = top;
237 	h->size = size;
238 	h->link = *l;
239 	*l = h;
240 	iunlock(&xlists);
241 }
242 
243 void
244 xsummary(void)
245 {
246 	int i;
247 	Hole *h;
248 
249 	i = 0;
250 	for(h = xlists.flist; h; h = h->link)
251 		i++;
252 
253 	print("%d holes free\n", i);
254 	i = 0;
255 	for(h = xlists.table; h; h = h->link) {
256 		print("%.8lux %.8lux %lud\n", h->addr, h->top, h->size);
257 		i += h->size;
258 	}
259 	print("%d bytes free\n", i);
260 }
261