#include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" typedef struct Chunk Chunk; typedef struct Chunkl Chunkl; typedef struct Arena Arena; enum { Minpow= 7, Maxpow= 12, }; struct Chunk { Chunk *next; }; struct Alloc { Lock; Chunk *first; int had; int goal; int last; }; struct Arena { Chunkl alloc[Maxpow-Minpow+1]; Chunkl freed; }; static Arena arena; /* * Manage interrupt level memory allocation. */ static void iallockproc(void *arg) { Chunk *p, *first, **l; Chunkl *cl; int pow, x, i; USED(arg); for(;;){ tsleep(&freed->r, return0, 0, 500); /* really free what was freed at interrupt level */ cl = &arena.freed; if(cl->first){ x = slphi(); lock(cl); first = cl->first; cl->first = 0; unlock(cl); spllo(); for(; first; first = p){ p = first->next; free(first); } } /* make sure we have blocks available for interrupt level */ for(pow = Minpow; pow <= Maxpow; pow++){ cl = &arena.alloc[pow]; if(cl->have >= cl->goal){ cl->had = cl->have; continue; } /* increase goal if we've been drained twice in a row */ if(cl->have == 0 && cl->had == 0) cl->goal += cl->goal>>2; cl->had = cl->have; l = &first; for(i = x = cl->goal - cl->have; x > 0; x--){ p = alloc(1<next; } if(first){ x = splhi(); lock(cl); *l = cl->first; cl->first = first; cl->have += i; unlock(cl); spllo(x); } } } } void iallocinit(void) { int pow; Chunkl *cl; for(pow = Minpow; pow <= Maxpow; pow++){ cl = &arena.alloc[pow]; cl->goal = Maxpow-pow + 4; } /* start garbage collector */ kproc("iallockproc", iallockproc, 0); } void* ialloc(int size) { int pow; Chunkl *cl; Chunk *p; for(pow = Min; pow <= Maxpow; pow++) if(size <= (1<first; if(p){ cl->have--; cl->first = p->next; } unlock(cl); return (void*)p; } panic("ialloc %d\n", size); } void ifree(void *a) { Chunk *p; Chunkl *cl; cl = &arena.freed; p = a; lock(cl); p->next = cl->first; cl->first = p; unlock(cl); } /* * allocate queues and blocks */ Block* allocb(int size) { Block *b; b = alloc(sizeof(Block) + size); if(b == 0) exhausted("blocks"); b->base = (uchar*)(b+1); b->rp = b->wp = b->base; b->lim = b->base + size; return b; } /* * Interrupt level copy out of a queue, return # bytes copied. If drop is * set, any bytes left in a block afer a consume are discarded. */ int consume(Queue *q, uchar *p, int len, int drop) { Block *b; int n; lock(q); b = q->first; if(b == 0){ q->state |= Qstarve; unlock(q); return -1; } n = BLEN(b); if(n < len) len = n; memmove(p, b->rp, len); if(len == n || drop){ q->first = b->next; ifree(b); } else b->rp += len; unlock(q); return len; } int produce(Queue *q, uchar *p, int len) { Block *b; b = ialloc(sizeof(Block) }