|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include "mem.h"
4: #include "dat.h"
5: #include "fns.h"
6: #include "error.h"
7:
8:
9: /*
10: * Plan 9 has two kernel allocators, the x... routines provide a first
11: * fit hole allocator which should be used for permanent or large structures.
12: * Routines are provided to allocate aligned memory which does not cross
13: * arbitrary 2^n boundaries. A second allocator malloc, smalloc, free is
14: * a 2n bucket allocator which steals from the x routines. This should
15: * be used for small frequently used structures.
16: */
17:
18: #define nil ((void*)0)
19: #define datoff ((ulong)((Xhdr*)0)->data)
20: #define bdatoff ((ulong)((Bucket*)0)->data)
21:
22: enum
23: {
24: Maxpow = 18,
25: CUTOFF = 12,
26: Nhole = 128,
27: Magichole = 0xDeadBabe,
28: Magic2n = 0xFeedBeef,
29: Spanlist = 64,
30:
31: NTRACE = 20,
32: };
33:
34: typedef struct Hole Hole;
35: typedef struct Xalloc Xalloc;
36: typedef struct Xhdr Xhdr;
37: typedef struct Bucket Bucket;
38: typedef struct Arena Arena;
39:
40: struct Hole
41: {
42: ulong addr;
43: ulong size;
44: ulong top;
45: Hole *link;
46: };
47:
48: struct Xhdr
49: {
50: ulong size;
51: ulong magix;
52: char data[1];
53: };
54:
55: struct Xalloc
56: {
57: Lock;
58: Hole hole[Nhole];
59: Hole *flist;
60: Hole *table;
61: };
62:
63: struct Bucket
64: {
65: int size;
66: int magic;
67: Bucket *next;
68: ulong pc;
69: char data[1];
70: };
71:
72: struct Arena
73: {
74: Lock;
75: Bucket *btab[Maxpow];
76: int nbuck[Maxpow];
77: struct{
78: ulong pc;
79: ulong alloc;
80: ulong free;
81: } trace[NTRACE];
82: QLock rq;
83: Rendez r;
84: };
85:
86: static Arena arena;
87: static Xalloc xlists;
88:
89: void
90: xinit(void)
91: {
92: Hole *h, *eh;
93: int up, np0, np1;
94:
95: eh = &xlists.hole[Nhole-1];
96: for(h = xlists.hole; h < eh; h++)
97: h->link = h+1;
98:
99: xlists.flist = xlists.hole;
100:
101: up = conf.upages;
102: np1 = up;
103: if(np1 > conf.npage1)
104: np1 = conf.npage1;
105:
106: palloc.p1 = conf.base1 + (conf.npage1 - np1)*BY2PG;
107: conf.npage1 -= np1;
108: xhole(conf.base1, conf.npage1*BY2PG);
109: conf.npage1 = conf.base1+(conf.npage1*BY2PG);
110: up -= np1;
111:
112: np0 = up;
113: if(np0 > conf.npage0)
114: np0 = conf.npage0;
115:
116: palloc.p0 = conf.base0 + (conf.npage0 - np0)*BY2PG;
117: conf.npage0 -= np0;
118: xhole(conf.base0, conf.npage0*BY2PG);
119: conf.npage0 = conf.base0+(conf.npage0*BY2PG);
120:
121: palloc.np0 = np0;
122: palloc.np1 = np1;
123: /* Save the bounds of kernel alloc memory for kernel mmu mapping */
124: conf.base0 = (ulong)KADDR(conf.base0);
125: conf.base1 = (ulong)KADDR(conf.base1);
126: conf.npage0 = (ulong)KADDR(conf.npage0);
127: conf.npage1 = (ulong)KADDR(conf.npage1);
128: }
129:
130: /*
131: * NB. spanalloc memory will cause a panic if free'd
132: */
133: void*
134: xspanalloc(ulong size, int align, ulong span)
135: {
136: int i, j;
137: ulong a, p, sinc;
138: ulong ptr[Spanlist];
139:
140: sinc = size/8;
141: span = ~(span-1);
142: for(i = 0; i < Spanlist; i++) {
143: p = (ulong)xalloc(size+align);
144: if(p == 0)
145: break;
146:
147: a = p+align;
148: a &= ~(align-1);
149: if((a&span) == ((a+size)&span)) {
150: for(j = 0; j < i; j++)
151: if(ptr[j])
152: xfree((void*)ptr[j]);
153:
154: return (void*)a;
155: }
156: xfree((void*)p);
157: ptr[i] = (ulong)xalloc(sinc);
158: }
159: USED(sinc);
160: xsummary();
161: panic("xspanalloc: %d %d %lux\n", size, align, span);
162: return 0;
163: }
164:
165: void*
166: xalloc(ulong size)
167: {
168: Xhdr *p;
169: Hole *h, **l;
170:
171: size += BY2WD + sizeof(Xhdr);
172: size &= ~(BY2WD-1);
173:
174: lock(&xlists);
175: l = &xlists.table;
176: for(h = *l; h; h = h->link) {
177: if(h->size >= size) {
178: p = (Xhdr*)h->addr;
179: h->addr += size;
180: h->size -= size;
181: if(h->size == 0) {
182: *l = h->link;
183: h->link = xlists.flist;
184: xlists.flist = h;
185: }
186: unlock(&xlists);
187: p = KADDR(p);
188: memset(p, 0, size);
189: p->magix = Magichole;
190: p->size = size;
191: return p->data;
192: }
193: l = &h->link;
194: }
195: unlock(&xlists);
196: return nil;
197: }
198:
199: void
200: xfree(void *p)
201: {
202: Xhdr *x;
203:
204: x = (Xhdr*)((ulong)p - datoff);
205: if(x->magix != Magichole)
206: panic("xfree");
207:
208: xhole(PADDR(x), x->size);
209: }
210:
211: void
212: xhole(ulong addr, ulong size)
213: {
214: ulong top;
215: Hole *h, *c, **l;
216:
217: if(size == 0)
218: return;
219:
220: top = addr + size;
221: lock(&xlists);
222: l = &xlists.table;
223: for(h = *l; h; h = h->link) {
224: if(h->top == addr) {
225: h->size += size;
226: h->top = h->addr+h->size;
227: c = h->link;
228: if(c && h->top == c->addr) {
229: h->top += c->size;
230: h->size += c->size;
231: h->link = c->link;
232: c->link = xlists.flist;
233: xlists.flist = c;
234: }
235: unlock(&xlists);
236: return;
237: }
238: if(h->addr > addr)
239: break;
240: l = &h->link;
241: }
242: if(h && top == h->addr) {
243: h->addr -= size;
244: h->size += size;
245: unlock(&xlists);
246: return;
247: }
248:
249: if(xlists.flist == nil) {
250: unlock(&xlists);
251: print("xfree: no free holes, leaked %d bytes\n", size);
252: return;
253: }
254:
255: h = xlists.flist;
256: xlists.flist = h->link;
257: h->addr = addr;
258: h->top = top;
259: h->size = size;
260: h->link = *l;
261: *l = h;
262: unlock(&xlists);
263: }
264:
265: void
266: alloctrace(void *p, ulong pc)
267: {
268: Bucket *bp;
269: int i;
270:
271: bp = (Bucket*)((ulong)p - bdatoff);
272: if(bp->size != 13)
273: return;
274: bp->pc = pc;
275: lock(&arena);
276: for(i = 0; i < NTRACE; i++){
277: if(arena.trace[i].pc == 0)
278: arena.trace[i].pc = pc;
279: if(arena.trace[i].pc == pc){
280: arena.trace[i].alloc++;
281: break;
282: }
283: }
284: unlock(&arena);
285: }
286:
287: void*
288: malloc(ulong size)
289: {
290: ulong next;
291: int pow, n;
292: Bucket *bp, *nbp;
293:
294: for(pow = 3; pow < Maxpow; pow++)
295: if(size <= (1<<pow))
296: goto good;
297:
298: return nil;
299: good:
300: /* Allocate off this list */
301: lock(&arena);
302: bp = arena.btab[pow];
303: if(bp) {
304: arena.btab[pow] = bp->next;
305: if(bp->magic != 0 || bp->size != pow){
306: unlock(&arena);
307: panic("malloc bp %lux magic %lux size %d next %lux pow %d", bp,
308: bp->magic, bp->size, bp->next, pow);
309: }
310: bp->magic = Magic2n;
311: unlock(&arena);
312:
313: memset(bp->data, 0, size);
314: bp->pc = getcallerpc(((uchar*)&size) - sizeof(size));
315: return bp->data;
316: }
317: unlock(&arena);
318:
319: size = sizeof(Bucket)+(1<<pow);
320: size += 3;
321: size &= ~3;
322:
323: if(pow < CUTOFF) {
324: n = (CUTOFF-pow)+2;
325: bp = xalloc(size*n);
326: if(bp == nil)
327: return nil;
328:
329: nbp = bp;
330: lock(&arena);
331: arena.nbuck[pow] += n;
332: while(--n) {
333: next = (ulong)nbp+size;
334: nbp = (Bucket*)next;
335: nbp->size = pow;
336: nbp->next = arena.btab[pow];
337: arena.btab[pow] = nbp;
338: }
339: unlock(&arena);
340: }
341: else {
342: bp = xalloc(size);
343: if(bp == nil)
344: return nil;
345:
346: arena.nbuck[pow]++;
347: }
348:
349: bp->size = pow;
350: bp->magic = Magic2n;
351: bp->pc = getcallerpc(((uchar*)&size) - sizeof(size));
352: return bp->data;
353: }
354:
355: void*
356: smalloc(ulong size)
357: {
358: char *s;
359: void *p;
360: int attempt;
361: Bucket *bp;
362:
363: for(attempt = 0; attempt < 1000; attempt++) {
364: p = malloc(size);
365: if(p != nil) {
366: bp = (Bucket*)((ulong)p - bdatoff);
367: bp->pc = getcallerpc(((uchar*)&size) - sizeof(size));
368: return p;
369: }
370: s = u->p->psstate;
371: u->p->psstate = "Malloc";
372: qlock(&arena.rq);
373: while(waserror())
374: ;
375: sleep(&arena.r, return0, nil);
376: poperror();
377: qunlock(&arena.rq);
378: u->p->psstate = s;
379: }
380: print("%s:%d: out of memory in smalloc %d\n", u->p->text, u->p->pid, size);
381: u->p->state = Broken;
382: u->p->psstate = "NoMem";
383: for(;;)
384: sched();
385: return 0;
386: }
387:
388: int
389: msize(void *ptr)
390: {
391: Bucket *bp;
392:
393: bp = (Bucket*)((ulong)ptr - bdatoff);
394: if(bp->magic != Magic2n)
395: panic("msize");
396: return 1<<bp->size;
397: }
398:
399: void
400: free(void *ptr)
401: {
402: ulong pc, n;
403: Bucket *bp, **l;
404:
405: bp = (Bucket*)((ulong)ptr - bdatoff);
406: l = &arena.btab[bp->size];
407:
408: lock(&arena);
409: if(bp->magic != Magic2n)
410: panic("free");
411: bp->magic = 0;
412: bp->next = *l;
413: *l = bp;
414: if(bp->size == 13) {
415: pc = bp->pc;
416: for(n = 0; n < NTRACE; n++){
417: if(arena.trace[n].pc == pc){
418: arena.trace[n].free++;
419: break;
420: }
421: }
422: }
423: unlock(&arena);
424: if(arena.r.p)
425: wakeup(&arena.r);
426: }
427:
428: void
429: xsummary(void)
430: {
431: Hole *h;
432: Bucket *k;
433: int i, nfree, nused;
434:
435: i = 0;
436: for(h = xlists.flist; h; h = h->link)
437: i++;
438:
439: print("%d holes free\n", i);
440: i = 0;
441: for(h = xlists.table; h; h = h->link) {
442: print("%.8lux %.8lux %d\n", h->addr, h->top, h->size);
443: i += h->size;
444: }
445: print("%d bytes free\n", i);
446: nused = 0;
447: for(i = 3; i < Maxpow; i++) {
448: if(arena.btab[i] == 0 && arena.nbuck[i] == 0)
449: continue;
450: nused += arena.nbuck[i]*(1<<i);
451: nfree = 0;
452: for(k = arena.btab[i]; k; k = k->next)
453: nfree++;
454: print("%8d %4d %4d\n", 1<<i, arena.nbuck[i], nfree);
455: }
456: for(i = 0; i < NTRACE && arena.trace[i].pc; i++)
457: print("%lux %d %d\n", arena.trace[i].pc, arena.trace[i].alloc, arena.trace[i].free);
458: print("%d bytes in pool\n", nused);
459: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.