#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" /* * Plan 9 has two kernel allocators, the x... routines provide a first * fit hole allocator which should be used for permanent or large structures. * Routines are provided to allocate aligned memory which does not cross * arbitrary 2^n boundaries. A second allocator malloc, smalloc, free is * a 2n bucket allocator which steals from the x routines. This should * be used for small frequently used structures. */ #define nil ((void*)0) #define datoff ((ulong)((Xhdr*)0)->data) #define bdatoff ((ulong)((Bucket*)0)->data) enum { Maxpow = 16, Nhole = 128, Magichole = 0xDeadBabe, Magic2n = 0xFeedBeef, Spanlist = 64, }; typedef struct Hole Hole; typedef struct Xalloc Xalloc; typedef struct Xhdr Xhdr; typedef struct Bucket Bucket; typedef struct Arena Arena; struct Hole { ulong addr; ulong size; ulong top; Hole *link; }; struct Xhdr { ulong size; ulong magix; char data[1]; }; struct Xalloc { Lock; Hole hole[Nhole]; Hole *flist; Hole *table; }; struct Bucket { int size; int magic; Bucket *next; char data[1]; }; struct Arena { Lock; Bucket *btab[Maxpow]; int nbuck[Maxpow]; }; static Arena arena; static Xalloc xlists; void* ialloc(ulong size, int align) { ulong p; if(align) { size += BY2PG; p = (ulong)xalloc(size); p += BY2PG; p &= ~(BY2PG-1); return (void*)p; } return xalloc(size);; } void xinit(void) { ulong ktop; Hole *h, *eh; int up, np0, np1; eh = &xlists.hole[Nhole-1]; for(h = xlists.hole; h < eh; h++) h->link = h+1; xlists.flist = xlists.hole; ktop = PGROUND((ulong)end); ktop = PADDR(ktop); conf.npage0 -= ktop/BY2PG; conf.base0 += ktop; up = conf.upages; np1 = up; if(np1 > conf.npage1) np1 = conf.npage1; palloc.p1 = conf.base1; conf.base1 += np1*BY2PG; conf.npage1 -= np1; xhole(conf.base1, conf.npage1*BY2PG); up -= np1; np0 = up; if(np0 > conf.npage0) np0 = conf.npage0; palloc.p0 = conf.base0; conf.base0 += np0*BY2PG; conf.npage0 -= np0; xhole(conf.base0, conf.npage0*BY2PG); palloc.np0 = np0; palloc.np1 = np1; } /* * NB. spanalloc memory will cause a panic if free'd */ void* xspanalloc(ulong size, int align, ulong span) { int i, j; ulong a, p; ulong ptr[Spanlist]; span = ~(span-1); for(i = 0; i < Spanlist; i++) { p = (ulong)xalloc(size+align); if(p == 0) panic("xspanalloc: size %d align %d span %d", size, align, span); a = p+align; a &= ~(align-1); if((a&span) == ((a+size)&span)) { for(j = 0; j < i; j++) xfree((void*)ptr[j]); return (void*)a; } ptr[i] = p; } panic("xspanalloc: spanlist"); return 0; } void* xalloc(ulong size) { Xhdr *p; Hole *h, **l; size += BY2WD + sizeof(Xhdr); size &= ~(BY2WD-1); lock(&xlists); l = &xlists.table; for(h = *l; h; h = h->link) { if(h->size >= size) { p = (Xhdr*)h->addr; h->addr += size; h->size -= size; if(h->size == 0) { *l = h->link; h->link = xlists.flist; xlists.flist = h; } p = KADDR(p); memset(p, 0, size); p->magix = Magichole; p->size = size; unlock(&xlists); return p->data; } l = &h->link; } unlock(&xlists); return nil; } void xfree(void *p) { Xhdr *x; x = (Xhdr*)((ulong)p - datoff); if(x->magix != Magichole) panic("xfree"); xhole(PADDR(x), x->size); } void xhole(ulong addr, ulong size) { ulong top; Hole *h, *c, **l; if(size == 0) return; top = addr + size; lock(&xlists); l = &xlists.table; for(h = *l; h; h = h->link) { if(h->top == addr) { h->size += size; h->top = h->addr+h->size; c = h->link; if(c && h->top == c->addr) { h->top += c->size; h->size += c->size; h->link = c->link; c->link = xlists.flist; xlists.flist = c; } unlock(&xlists); return; } if(h->addr > addr) break; l = &h->link; } if(h && top == h->addr) { h->addr -= size; h->size += size; unlock(&xlists); return; } if(xlists.flist == nil) { unlock(&xlists); print("xfree: no free holes, leaked %d bytes\n", size); return; } h = xlists.flist; xlists.flist = h->link; h->addr = addr; h->top = top; h->size = size; h->link = *l; *l = h; unlock(&xlists); } void* malloc(ulong size) { int pow; Bucket *bp; for(pow = 3; pow < Maxpow; pow++) if(size <= (1<next; unlock(&arena); if(bp->magic != 0) panic("malloc"); bp->magic = Magic2n; memset(bp->data, 0, size); return bp->data; } arena.nbuck[pow]++; unlock(&arena); size = sizeof(Bucket)+(1<size = pow; bp->magic = Magic2n; return bp->data; } void* smalloc(ulong size) { void *p; p = malloc(size); if(p == nil) panic("smalloc should sleep"); return p; } void free(void *ptr) { Bucket *bp, **l; bp = (Bucket*)((ulong)ptr - bdatoff); if(bp->magic != Magic2n) panic("free"); bp->magic = 0; lock(&arena); l = &arena.btab[bp->size]; bp->next = *l; *l = bp; unlock(&arena); } void xsummary(void) { Hole *h; Bucket *k; int i, nfree; i = 0; for(h = xlists.flist; h; h = h->link) i++; print("%d holes free\n", i); i = 0; for(h = xlists.table; h; h = h->link) { print("%.8lux %.8lux %d\n", h->addr, h->top, h->size); i += h->size; } print("%d bytes free\n", i); for(i = 3; i < Maxpow; i++) { if(arena.btab[i] == 0 && arena.nbuck[i] == 0) continue; nfree = 0; for(k = arena.btab[i]; k; k = k->next) nfree++; print("%8d %4d %4d\n", 1<