17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * area-based allocation built on malloc/free
37dd7cddfSDavid du Colombier */
47dd7cddfSDavid du Colombier
57dd7cddfSDavid du Colombier #include "sh.h"
67dd7cddfSDavid du Colombier
77dd7cddfSDavid du Colombier
87dd7cddfSDavid du Colombier
97dd7cddfSDavid du Colombier # if DEBUG_ALLOC
107dd7cddfSDavid du Colombier void acheck ARGS((Area *ap));
117dd7cddfSDavid du Colombier # define ACHECK(ap) acheck(ap)
127dd7cddfSDavid du Colombier # else /* DEBUG_ALLOC */
137dd7cddfSDavid du Colombier # define ACHECK(ap)
147dd7cddfSDavid du Colombier # endif /* DEBUG_ALLOC */
157dd7cddfSDavid du Colombier
167dd7cddfSDavid du Colombier #define ICELLS 200 /* number of Cells in small Block */
177dd7cddfSDavid du Colombier
187dd7cddfSDavid du Colombier typedef union Cell Cell;
197dd7cddfSDavid du Colombier typedef struct Block Block;
207dd7cddfSDavid du Colombier
217dd7cddfSDavid du Colombier /*
227dd7cddfSDavid du Colombier * The Cells in a Block are organized as a set of objects.
237dd7cddfSDavid du Colombier * Each object (pointed to by dp) begins with the block it is in
247dd7cddfSDavid du Colombier * (dp-2)->block, then has a size in (dp-1)->size, which is
257dd7cddfSDavid du Colombier * followed with "size" data Cells. Free objects are
267dd7cddfSDavid du Colombier * linked together via dp->next.
277dd7cddfSDavid du Colombier */
287dd7cddfSDavid du Colombier
297dd7cddfSDavid du Colombier #define NOBJECT_FIELDS 2 /* the block and size `fields' */
307dd7cddfSDavid du Colombier
317dd7cddfSDavid du Colombier union Cell {
327dd7cddfSDavid du Colombier size_t size;
337dd7cddfSDavid du Colombier Cell *next;
347dd7cddfSDavid du Colombier Block *block;
357dd7cddfSDavid du Colombier struct {int _;} junk; /* alignment */
367dd7cddfSDavid du Colombier double djunk; /* alignment */
377dd7cddfSDavid du Colombier };
387dd7cddfSDavid du Colombier
397dd7cddfSDavid du Colombier struct Block {
407dd7cddfSDavid du Colombier Block *next; /* list of Blocks in Area */
417dd7cddfSDavid du Colombier Block *prev; /* previous block in list */
427dd7cddfSDavid du Colombier Cell *freelist; /* object free list */
437dd7cddfSDavid du Colombier Cell *last; /* &b.cell[size] */
447dd7cddfSDavid du Colombier Cell cell [1]; /* [size] Cells for allocation */
457dd7cddfSDavid du Colombier };
467dd7cddfSDavid du Colombier
477dd7cddfSDavid du Colombier static Block aempty = {&aempty, &aempty, aempty.cell, aempty.cell};
487dd7cddfSDavid du Colombier
497dd7cddfSDavid du Colombier static void ablockfree ARGS((Block *bp, Area *ap));
507dd7cddfSDavid du Colombier static void *asplit ARGS((Area *ap, Block *bp, Cell *fp, Cell *fpp, int cells));
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier /* create empty Area */
537dd7cddfSDavid du Colombier Area *
ainit(ap)547dd7cddfSDavid du Colombier ainit(ap)
557dd7cddfSDavid du Colombier register Area *ap;
567dd7cddfSDavid du Colombier {
577dd7cddfSDavid du Colombier ap->freelist = &aempty;
587dd7cddfSDavid du Colombier ACHECK(ap);
597dd7cddfSDavid du Colombier return ap;
607dd7cddfSDavid du Colombier }
617dd7cddfSDavid du Colombier
627dd7cddfSDavid du Colombier /* free all object in Area */
637dd7cddfSDavid du Colombier void
afreeall(ap)647dd7cddfSDavid du Colombier afreeall(ap)
657dd7cddfSDavid du Colombier register Area *ap;
667dd7cddfSDavid du Colombier {
677dd7cddfSDavid du Colombier register Block *bp;
687dd7cddfSDavid du Colombier register Block *tmp;
697dd7cddfSDavid du Colombier
707dd7cddfSDavid du Colombier ACHECK(ap);
717dd7cddfSDavid du Colombier bp = ap->freelist;
727dd7cddfSDavid du Colombier if (bp != NULL && bp != &aempty) {
737dd7cddfSDavid du Colombier do {
747dd7cddfSDavid du Colombier tmp = bp;
757dd7cddfSDavid du Colombier bp = bp->next;
767dd7cddfSDavid du Colombier free((void*)tmp);
777dd7cddfSDavid du Colombier } while (bp != ap->freelist);
787dd7cddfSDavid du Colombier ap->freelist = &aempty;
797dd7cddfSDavid du Colombier }
807dd7cddfSDavid du Colombier ACHECK(ap);
817dd7cddfSDavid du Colombier }
827dd7cddfSDavid du Colombier
837dd7cddfSDavid du Colombier /* allocate object from Area */
847dd7cddfSDavid du Colombier void *
alloc(size,ap)857dd7cddfSDavid du Colombier alloc(size, ap)
867dd7cddfSDavid du Colombier size_t size;
877dd7cddfSDavid du Colombier register Area *ap;
887dd7cddfSDavid du Colombier {
897dd7cddfSDavid du Colombier int cells, acells;
907dd7cddfSDavid du Colombier Block *bp = 0;
917dd7cddfSDavid du Colombier Cell *fp = 0, *fpp = 0;
927dd7cddfSDavid du Colombier
937dd7cddfSDavid du Colombier ACHECK(ap);
947dd7cddfSDavid du Colombier if (size <= 0)
957dd7cddfSDavid du Colombier aerror(ap, "allocate bad size");
967dd7cddfSDavid du Colombier cells = (unsigned)(size + sizeof(Cell) - 1) / sizeof(Cell);
977dd7cddfSDavid du Colombier
987dd7cddfSDavid du Colombier /* allocate at least this many cells */
997dd7cddfSDavid du Colombier acells = cells + NOBJECT_FIELDS;
1007dd7cddfSDavid du Colombier
1017dd7cddfSDavid du Colombier /*
1027dd7cddfSDavid du Colombier * Only attempt to track small objects - let malloc deal
1037dd7cddfSDavid du Colombier * with larger objects. (this way we don't have to deal with
1047dd7cddfSDavid du Colombier * coalescing memory, or with releasing it to the system)
1057dd7cddfSDavid du Colombier */
1067dd7cddfSDavid du Colombier if (cells <= ICELLS) {
1077dd7cddfSDavid du Colombier /* find free Cell large enough */
1087dd7cddfSDavid du Colombier for (bp = ap->freelist; ; bp = bp->next) {
1097dd7cddfSDavid du Colombier for (fpp = NULL, fp = bp->freelist;
1107dd7cddfSDavid du Colombier fp != bp->last; fpp = fp, fp = fp->next)
1117dd7cddfSDavid du Colombier {
1127dd7cddfSDavid du Colombier if ((fp-1)->size >= cells)
1137dd7cddfSDavid du Colombier goto Found;
1147dd7cddfSDavid du Colombier }
1157dd7cddfSDavid du Colombier /* wrapped around Block list, create new Block */
1167dd7cddfSDavid du Colombier if (bp->next == ap->freelist) {
1177dd7cddfSDavid du Colombier bp = 0;
1187dd7cddfSDavid du Colombier break;
1197dd7cddfSDavid du Colombier }
1207dd7cddfSDavid du Colombier }
1217dd7cddfSDavid du Colombier /* Not much free space left? Allocate a big object this time */
1227dd7cddfSDavid du Colombier acells += ICELLS;
1237dd7cddfSDavid du Colombier }
1247dd7cddfSDavid du Colombier if (bp == 0) {
1257dd7cddfSDavid du Colombier bp = (Block*) malloc(offsetof(Block, cell[acells]));
1267dd7cddfSDavid du Colombier if (bp == NULL)
1277dd7cddfSDavid du Colombier aerror(ap, "cannot allocate");
1287dd7cddfSDavid du Colombier if (ap->freelist == &aempty) {
1297dd7cddfSDavid du Colombier ap->freelist = bp->next = bp->prev = bp;
1307dd7cddfSDavid du Colombier } else {
1317dd7cddfSDavid du Colombier bp->next = ap->freelist->next;
1327dd7cddfSDavid du Colombier ap->freelist->next->prev = bp;
1337dd7cddfSDavid du Colombier ap->freelist->next = bp;
1347dd7cddfSDavid du Colombier bp->prev = ap->freelist;
1357dd7cddfSDavid du Colombier }
1367dd7cddfSDavid du Colombier bp->last = bp->cell + acells;
1377dd7cddfSDavid du Colombier /* initial free list */
1387dd7cddfSDavid du Colombier fp = bp->freelist = bp->cell + NOBJECT_FIELDS;
1397dd7cddfSDavid du Colombier (fp-1)->size = acells - NOBJECT_FIELDS;
1407dd7cddfSDavid du Colombier (fp-2)->block = bp;
1417dd7cddfSDavid du Colombier fp->next = bp->last;
1427dd7cddfSDavid du Colombier fpp = NULL;
1437dd7cddfSDavid du Colombier }
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier Found:
1467dd7cddfSDavid du Colombier return asplit(ap, bp, fp, fpp, cells);
1477dd7cddfSDavid du Colombier }
1487dd7cddfSDavid du Colombier
1497dd7cddfSDavid du Colombier /* Do the work of splitting an object into allocated and (possibly) unallocated
1507dd7cddfSDavid du Colombier * objects. Returns the `allocated' object.
1517dd7cddfSDavid du Colombier */
1527dd7cddfSDavid du Colombier static void *
asplit(ap,bp,fp,fpp,cells)1537dd7cddfSDavid du Colombier asplit(ap, bp, fp, fpp, cells)
1547dd7cddfSDavid du Colombier Area *ap;
1557dd7cddfSDavid du Colombier Block *bp;
1567dd7cddfSDavid du Colombier Cell *fp;
1577dd7cddfSDavid du Colombier Cell *fpp;
1587dd7cddfSDavid du Colombier int cells;
1597dd7cddfSDavid du Colombier {
1607dd7cddfSDavid du Colombier Cell *dp = fp; /* allocated object */
1617dd7cddfSDavid du Colombier int split = (fp-1)->size - cells;
1627dd7cddfSDavid du Colombier
1637dd7cddfSDavid du Colombier ACHECK(ap);
1647dd7cddfSDavid du Colombier if (split < 0)
1657dd7cddfSDavid du Colombier aerror(ap, "allocated object too small");
1667dd7cddfSDavid du Colombier if (split <= NOBJECT_FIELDS) { /* allocate all */
1677dd7cddfSDavid du Colombier fp = fp->next;
1687dd7cddfSDavid du Colombier } else { /* allocate head, free tail */
1697dd7cddfSDavid du Colombier Cell *next = fp->next; /* needed, as cells may be 0 */
1707dd7cddfSDavid du Colombier ap->freelist = bp; /* next time, start looking for space here */
1717dd7cddfSDavid du Colombier (fp-1)->size = cells;
1727dd7cddfSDavid du Colombier fp += cells + NOBJECT_FIELDS;
1737dd7cddfSDavid du Colombier (fp-1)->size = split - NOBJECT_FIELDS;
1747dd7cddfSDavid du Colombier (fp-2)->block = bp;
1757dd7cddfSDavid du Colombier fp->next = next;
1767dd7cddfSDavid du Colombier }
1777dd7cddfSDavid du Colombier if (fpp == NULL)
1787dd7cddfSDavid du Colombier bp->freelist = fp;
1797dd7cddfSDavid du Colombier else
1807dd7cddfSDavid du Colombier fpp->next = fp;
1817dd7cddfSDavid du Colombier ACHECK(ap);
1827dd7cddfSDavid du Colombier return (void*) dp;
1837dd7cddfSDavid du Colombier }
1847dd7cddfSDavid du Colombier
1857dd7cddfSDavid du Colombier /* change size of object -- like realloc */
1867dd7cddfSDavid du Colombier void *
aresize(ptr,size,ap)1877dd7cddfSDavid du Colombier aresize(ptr, size, ap)
1887dd7cddfSDavid du Colombier register void *ptr;
1897dd7cddfSDavid du Colombier size_t size;
1907dd7cddfSDavid du Colombier Area *ap;
1917dd7cddfSDavid du Colombier {
1927dd7cddfSDavid du Colombier int cells;
1937dd7cddfSDavid du Colombier Cell *dp = (Cell*) ptr;
1947dd7cddfSDavid du Colombier int oldcells = dp ? (dp-1)->size : 0;
1957dd7cddfSDavid du Colombier
1967dd7cddfSDavid du Colombier ACHECK(ap);
1977dd7cddfSDavid du Colombier if (size <= 0)
1987dd7cddfSDavid du Colombier aerror(ap, "allocate bad size");
1997dd7cddfSDavid du Colombier /* New size (in cells) */
2007dd7cddfSDavid du Colombier cells = (unsigned)(size - 1) / sizeof(Cell) + 1;
2017dd7cddfSDavid du Colombier
2027dd7cddfSDavid du Colombier /* Is this a large object? If so, let malloc deal with it
2037dd7cddfSDavid du Colombier * directly (unless we are crossing the ICELLS border, in
2047dd7cddfSDavid du Colombier * which case the alloc/free below handles it - this should
2057dd7cddfSDavid du Colombier * cut down on fragmentation, and will also keep the code
2067dd7cddfSDavid du Colombier * working (as it assumes size < ICELLS means it is not
2077dd7cddfSDavid du Colombier * a `large object').
2087dd7cddfSDavid du Colombier */
2097dd7cddfSDavid du Colombier if (oldcells > ICELLS && cells > ICELLS) {
2107dd7cddfSDavid du Colombier Block *bp = (dp-2)->block;
2117dd7cddfSDavid du Colombier Block *nbp;
2127dd7cddfSDavid du Colombier /* Saved in case realloc fails.. */
2137dd7cddfSDavid du Colombier Block *next = bp->next, *prev = bp->prev;
2147dd7cddfSDavid du Colombier
2157dd7cddfSDavid du Colombier if (bp->freelist != bp->last)
2167dd7cddfSDavid du Colombier aerror(ap, "allocation resizing free pointer");
2177dd7cddfSDavid du Colombier nbp = realloc((void *) bp,
2187dd7cddfSDavid du Colombier offsetof(Block, cell[cells + NOBJECT_FIELDS]));
2197dd7cddfSDavid du Colombier if (!nbp) {
2207dd7cddfSDavid du Colombier /* Have to clean up... */
2217dd7cddfSDavid du Colombier /* NOTE: If this code changes, similar changes may be
2227dd7cddfSDavid du Colombier * needed in ablockfree().
2237dd7cddfSDavid du Colombier */
2247dd7cddfSDavid du Colombier if (next == bp) /* only block */
2257dd7cddfSDavid du Colombier ap->freelist = &aempty;
2267dd7cddfSDavid du Colombier else {
2277dd7cddfSDavid du Colombier next->prev = prev;
2287dd7cddfSDavid du Colombier prev->next = next;
2297dd7cddfSDavid du Colombier if (ap->freelist == bp)
2307dd7cddfSDavid du Colombier ap->freelist = next;
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier aerror(ap, "cannot re-allocate");
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier /* If location changed, keep pointers straight... */
2357dd7cddfSDavid du Colombier if (nbp != bp) {
2367dd7cddfSDavid du Colombier if (next == bp) /* only one block */
2377dd7cddfSDavid du Colombier nbp->next = nbp->prev = nbp;
2387dd7cddfSDavid du Colombier else {
2397dd7cddfSDavid du Colombier next->prev = nbp;
2407dd7cddfSDavid du Colombier prev->next = nbp;
2417dd7cddfSDavid du Colombier }
2427dd7cddfSDavid du Colombier if (ap->freelist == bp)
2437dd7cddfSDavid du Colombier ap->freelist = nbp;
2447dd7cddfSDavid du Colombier dp = nbp->cell + NOBJECT_FIELDS;
2457dd7cddfSDavid du Colombier (dp-2)->block = nbp;
2467dd7cddfSDavid du Colombier }
2477dd7cddfSDavid du Colombier (dp-1)->size = cells;
2487dd7cddfSDavid du Colombier nbp->last = nbp->cell + cells + NOBJECT_FIELDS;
2497dd7cddfSDavid du Colombier nbp->freelist = nbp->last;
2507dd7cddfSDavid du Colombier
2517dd7cddfSDavid du Colombier ACHECK(ap);
2527dd7cddfSDavid du Colombier return (void*) dp;
2537dd7cddfSDavid du Colombier }
2547dd7cddfSDavid du Colombier
2557dd7cddfSDavid du Colombier /* Check if we can just grow this cell
2567dd7cddfSDavid du Colombier * (need to check that cells < ICELLS so we don't make an
2577dd7cddfSDavid du Colombier * object a `large' - that would mess everything up).
2587dd7cddfSDavid du Colombier */
2597dd7cddfSDavid du Colombier if (dp && cells > oldcells && cells <= ICELLS) {
2607dd7cddfSDavid du Colombier Cell *fp, *fpp;
2617dd7cddfSDavid du Colombier Block *bp = (dp-2)->block;
2627dd7cddfSDavid du Colombier int need = cells - oldcells - NOBJECT_FIELDS;
2637dd7cddfSDavid du Colombier
2647dd7cddfSDavid du Colombier /* XXX if we had a flag in an object indicating
2657dd7cddfSDavid du Colombier * if the object was free/allocated, we could
2667dd7cddfSDavid du Colombier * avoid this loop (perhaps)
2677dd7cddfSDavid du Colombier */
2687dd7cddfSDavid du Colombier for (fpp = NULL, fp = bp->freelist;
2697dd7cddfSDavid du Colombier fp != bp->last
2707dd7cddfSDavid du Colombier && dp + oldcells + NOBJECT_FIELDS <= fp
2717dd7cddfSDavid du Colombier ; fpp = fp, fp = fp->next)
2727dd7cddfSDavid du Colombier {
2737dd7cddfSDavid du Colombier if (dp + oldcells + NOBJECT_FIELDS == fp
2747dd7cddfSDavid du Colombier && (fp-1)->size >= need)
2757dd7cddfSDavid du Colombier {
2767dd7cddfSDavid du Colombier Cell *np = asplit(ap, bp, fp, fpp, need);
2777dd7cddfSDavid du Colombier /* May get more than we need here */
2787dd7cddfSDavid du Colombier (dp-1)->size += (np-1)->size + NOBJECT_FIELDS;
2797dd7cddfSDavid du Colombier ACHECK(ap);
2807dd7cddfSDavid du Colombier return ptr;
2817dd7cddfSDavid du Colombier }
2827dd7cddfSDavid du Colombier }
2837dd7cddfSDavid du Colombier }
2847dd7cddfSDavid du Colombier
2857dd7cddfSDavid du Colombier /* Check if we can just shrink this cell
2867dd7cddfSDavid du Colombier * (if oldcells > ICELLS, this is a large object and we leave
2877dd7cddfSDavid du Colombier * it to malloc...)
2887dd7cddfSDavid du Colombier * Note: this also handles cells == oldcells (a no-op).
2897dd7cddfSDavid du Colombier */
2907dd7cddfSDavid du Colombier if (dp && cells <= oldcells && oldcells <= ICELLS) {
2917dd7cddfSDavid du Colombier int split;
2927dd7cddfSDavid du Colombier
2937dd7cddfSDavid du Colombier split = oldcells - cells;
2947dd7cddfSDavid du Colombier if (split <= NOBJECT_FIELDS) /* cannot split */
2957dd7cddfSDavid du Colombier ;
2967dd7cddfSDavid du Colombier else { /* shrink head, free tail */
2977dd7cddfSDavid du Colombier Block *bp = (dp-2)->block;
2987dd7cddfSDavid du Colombier
2997dd7cddfSDavid du Colombier (dp-1)->size = cells;
3007dd7cddfSDavid du Colombier dp += cells + NOBJECT_FIELDS;
3017dd7cddfSDavid du Colombier (dp-1)->size = split - NOBJECT_FIELDS;
3027dd7cddfSDavid du Colombier (dp-2)->block = bp;
3037dd7cddfSDavid du Colombier afree((void*)dp, ap);
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier /* ACHECK() done in afree() */
3067dd7cddfSDavid du Colombier return ptr;
3077dd7cddfSDavid du Colombier }
3087dd7cddfSDavid du Colombier
3097dd7cddfSDavid du Colombier /* Have to do it the hard way... */
3107dd7cddfSDavid du Colombier ptr = alloc(size, ap);
3117dd7cddfSDavid du Colombier if (dp != NULL) {
3127dd7cddfSDavid du Colombier size_t s = (dp-1)->size * sizeof(Cell);
3137dd7cddfSDavid du Colombier if (s > size)
3147dd7cddfSDavid du Colombier s = size;
3157dd7cddfSDavid du Colombier memcpy(ptr, dp, s);
3167dd7cddfSDavid du Colombier afree((void *) dp, ap);
3177dd7cddfSDavid du Colombier }
3187dd7cddfSDavid du Colombier /* ACHECK() done in alloc()/afree() */
3197dd7cddfSDavid du Colombier return ptr;
3207dd7cddfSDavid du Colombier }
3217dd7cddfSDavid du Colombier
3227dd7cddfSDavid du Colombier void
afree(ptr,ap)3237dd7cddfSDavid du Colombier afree(ptr, ap)
3247dd7cddfSDavid du Colombier void *ptr;
3257dd7cddfSDavid du Colombier register Area *ap;
3267dd7cddfSDavid du Colombier {
3277dd7cddfSDavid du Colombier register Block *bp;
3287dd7cddfSDavid du Colombier register Cell *fp, *fpp;
3297dd7cddfSDavid du Colombier register Cell *dp = (Cell*)ptr;
3307dd7cddfSDavid du Colombier
3317dd7cddfSDavid du Colombier ACHECK(ap);
3327dd7cddfSDavid du Colombier if (ptr == 0)
3337dd7cddfSDavid du Colombier aerror(ap, "freeing null pointer");
3347dd7cddfSDavid du Colombier bp = (dp-2)->block;
3357dd7cddfSDavid du Colombier
3367dd7cddfSDavid du Colombier /* If this is a large object, just free it up... */
3377dd7cddfSDavid du Colombier /* Release object... */
3387dd7cddfSDavid du Colombier if ((dp-1)->size > ICELLS) {
3397dd7cddfSDavid du Colombier ablockfree(bp, ap);
3407dd7cddfSDavid du Colombier ACHECK(ap);
3417dd7cddfSDavid du Colombier return;
3427dd7cddfSDavid du Colombier }
3437dd7cddfSDavid du Colombier
3447dd7cddfSDavid du Colombier if (dp < &bp->cell[NOBJECT_FIELDS] || dp >= bp->last)
3457dd7cddfSDavid du Colombier aerror(ap, "freeing memory outside of block (corrupted?)");
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier /* find position in free list */
3487dd7cddfSDavid du Colombier /* XXX if we had prev/next pointers for objects, this loop could go */
3497dd7cddfSDavid du Colombier for (fpp = NULL, fp = bp->freelist; fp < dp; fpp = fp, fp = fp->next)
3507dd7cddfSDavid du Colombier ;
3517dd7cddfSDavid du Colombier
3527dd7cddfSDavid du Colombier if (fp == dp)
3537dd7cddfSDavid du Colombier aerror(ap, "freeing free object");
3547dd7cddfSDavid du Colombier
3557dd7cddfSDavid du Colombier /* join object with next */
3567dd7cddfSDavid du Colombier if (dp + (dp-1)->size == fp-NOBJECT_FIELDS) { /* adjacent */
3577dd7cddfSDavid du Colombier (dp-1)->size += (fp-1)->size + NOBJECT_FIELDS;
3587dd7cddfSDavid du Colombier dp->next = fp->next;
3597dd7cddfSDavid du Colombier } else /* non-adjacent */
3607dd7cddfSDavid du Colombier dp->next = fp;
3617dd7cddfSDavid du Colombier
3627dd7cddfSDavid du Colombier /* join previous with object */
3637dd7cddfSDavid du Colombier if (fpp == NULL)
3647dd7cddfSDavid du Colombier bp->freelist = dp;
3657dd7cddfSDavid du Colombier else if (fpp + (fpp-1)->size == dp-NOBJECT_FIELDS) { /* adjacent */
3667dd7cddfSDavid du Colombier (fpp-1)->size += (dp-1)->size + NOBJECT_FIELDS;
3677dd7cddfSDavid du Colombier fpp->next = dp->next;
3687dd7cddfSDavid du Colombier } else /* non-adjacent */
3697dd7cddfSDavid du Colombier fpp->next = dp;
3707dd7cddfSDavid du Colombier
3717dd7cddfSDavid du Colombier /* If whole block is free (and we have some other blocks
3727dd7cddfSDavid du Colombier * around), release this block back to the system...
3737dd7cddfSDavid du Colombier */
3747dd7cddfSDavid du Colombier if (bp->next != bp && bp->freelist == bp->cell + NOBJECT_FIELDS
3757dd7cddfSDavid du Colombier && bp->freelist + (bp->freelist-1)->size == bp->last
3767dd7cddfSDavid du Colombier /* XXX and the other block has some free memory? */
3777dd7cddfSDavid du Colombier )
3787dd7cddfSDavid du Colombier ablockfree(bp, ap);
3797dd7cddfSDavid du Colombier ACHECK(ap);
3807dd7cddfSDavid du Colombier }
3817dd7cddfSDavid du Colombier
3827dd7cddfSDavid du Colombier static void
ablockfree(bp,ap)3837dd7cddfSDavid du Colombier ablockfree(bp, ap)
3847dd7cddfSDavid du Colombier Block *bp;
3857dd7cddfSDavid du Colombier Area *ap;
3867dd7cddfSDavid du Colombier {
3877dd7cddfSDavid du Colombier /* NOTE: If this code changes, similar changes may be
3887dd7cddfSDavid du Colombier * needed in alloc() (where realloc fails).
3897dd7cddfSDavid du Colombier */
3907dd7cddfSDavid du Colombier
3917dd7cddfSDavid du Colombier if (bp->next == bp) /* only block */
3927dd7cddfSDavid du Colombier ap->freelist = &aempty;
3937dd7cddfSDavid du Colombier else {
3947dd7cddfSDavid du Colombier bp->next->prev = bp->prev;
3957dd7cddfSDavid du Colombier bp->prev->next = bp->next;
3967dd7cddfSDavid du Colombier if (ap->freelist == bp)
3977dd7cddfSDavid du Colombier ap->freelist = bp->next;
3987dd7cddfSDavid du Colombier }
3997dd7cddfSDavid du Colombier free((void*) bp);
4007dd7cddfSDavid du Colombier }
4017dd7cddfSDavid du Colombier
4027dd7cddfSDavid du Colombier # if DEBUG_ALLOC
4037dd7cddfSDavid du Colombier void
acheck(ap)4047dd7cddfSDavid du Colombier acheck(ap)
4057dd7cddfSDavid du Colombier Area *ap;
4067dd7cddfSDavid du Colombier {
4077dd7cddfSDavid du Colombier Block *bp, *bpp;
4087dd7cddfSDavid du Colombier Cell *dp, *dptmp, *fp;
4097dd7cddfSDavid du Colombier int ok = 1;
4107dd7cddfSDavid du Colombier int isfree;
4117dd7cddfSDavid du Colombier static int disabled;
4127dd7cddfSDavid du Colombier
4137dd7cddfSDavid du Colombier if (disabled)
4147dd7cddfSDavid du Colombier return;
4157dd7cddfSDavid du Colombier
4167dd7cddfSDavid du Colombier if (!ap) {
4177dd7cddfSDavid du Colombier disabled = 1;
4187dd7cddfSDavid du Colombier aerror(ap, "acheck: null area pointer");
4197dd7cddfSDavid du Colombier }
4207dd7cddfSDavid du Colombier
4217dd7cddfSDavid du Colombier bp = ap->freelist;
4227dd7cddfSDavid du Colombier if (!bp) {
4237dd7cddfSDavid du Colombier disabled = 1;
4247dd7cddfSDavid du Colombier aerror(ap, "acheck: null area freelist");
4257dd7cddfSDavid du Colombier }
4267dd7cddfSDavid du Colombier
4277dd7cddfSDavid du Colombier /* Nothing to check... */
4287dd7cddfSDavid du Colombier if (bp == &aempty)
4297dd7cddfSDavid du Colombier return;
4307dd7cddfSDavid du Colombier
4317dd7cddfSDavid du Colombier bpp = ap->freelist->prev;
4327dd7cddfSDavid du Colombier while (1) {
4337dd7cddfSDavid du Colombier if (bp->prev != bpp) {
4347dd7cddfSDavid du Colombier shellf("acheck: bp->prev != previous\n");
4357dd7cddfSDavid du Colombier ok = 0;
4367dd7cddfSDavid du Colombier }
4377dd7cddfSDavid du Colombier fp = bp->freelist;
4387dd7cddfSDavid du Colombier for (dp = &bp->cell[NOBJECT_FIELDS]; dp != bp->last; ) {
4397dd7cddfSDavid du Colombier if ((dp-2)->block != bp) {
4407dd7cddfSDavid du Colombier shellf("acheck: fragment's block is wrong\n");
4417dd7cddfSDavid du Colombier ok = 0;
4427dd7cddfSDavid du Colombier }
4437dd7cddfSDavid du Colombier isfree = dp == fp;
4447dd7cddfSDavid du Colombier if ((dp-1)->size == 0 && isfree) {
4457dd7cddfSDavid du Colombier shellf("acheck: 0 size frag\n");
4467dd7cddfSDavid du Colombier ok = 0;
4477dd7cddfSDavid du Colombier }
4487dd7cddfSDavid du Colombier if ((dp-1)->size > ICELLS
4497dd7cddfSDavid du Colombier && !isfree
4507dd7cddfSDavid du Colombier && (dp != &bp->cell[NOBJECT_FIELDS]
4517dd7cddfSDavid du Colombier || dp + (dp-1)->size != bp->last))
4527dd7cddfSDavid du Colombier {
4537dd7cddfSDavid du Colombier shellf("acheck: big cell doesn't make up whole block\n");
4547dd7cddfSDavid du Colombier ok = 0;
4557dd7cddfSDavid du Colombier }
4567dd7cddfSDavid du Colombier if (isfree) {
4577dd7cddfSDavid du Colombier if (dp->next <= dp) {
4587dd7cddfSDavid du Colombier shellf("acheck: free fragment's next <= self\n");
4597dd7cddfSDavid du Colombier ok = 0;
4607dd7cddfSDavid du Colombier }
4617dd7cddfSDavid du Colombier if (dp->next > bp->last) {
4627dd7cddfSDavid du Colombier shellf("acheck: free fragment's next > last\n");
4637dd7cddfSDavid du Colombier ok = 0;
4647dd7cddfSDavid du Colombier }
4657dd7cddfSDavid du Colombier fp = dp->next;
4667dd7cddfSDavid du Colombier }
4677dd7cddfSDavid du Colombier dptmp = dp + (dp-1)->size;
4687dd7cddfSDavid du Colombier if (dptmp > bp->last) {
4697dd7cddfSDavid du Colombier shellf("acheck: next frag out of range\n");
4707dd7cddfSDavid du Colombier ok = 0;
4717dd7cddfSDavid du Colombier break;
4727dd7cddfSDavid du Colombier } else if (dptmp != bp->last) {
4737dd7cddfSDavid du Colombier dptmp += NOBJECT_FIELDS;
4747dd7cddfSDavid du Colombier if (dptmp > bp->last) {
4757dd7cddfSDavid du Colombier shellf("acheck: next frag just out of range\n");
4767dd7cddfSDavid du Colombier ok = 0;
4777dd7cddfSDavid du Colombier break;
4787dd7cddfSDavid du Colombier }
4797dd7cddfSDavid du Colombier }
4807dd7cddfSDavid du Colombier if (isfree && dptmp == fp && dptmp != bp->last) {
4817dd7cddfSDavid du Colombier shellf("acheck: adjacent free frags\n");
4827dd7cddfSDavid du Colombier ok = 0;
4837dd7cddfSDavid du Colombier } else if (dptmp > fp) {
4847dd7cddfSDavid du Colombier shellf("acheck: free frag list messed up\n");
4857dd7cddfSDavid du Colombier ok = 0;
4867dd7cddfSDavid du Colombier }
4877dd7cddfSDavid du Colombier dp = dptmp;
4887dd7cddfSDavid du Colombier }
4897dd7cddfSDavid du Colombier bpp = bp;
4907dd7cddfSDavid du Colombier bp = bp->next;
4917dd7cddfSDavid du Colombier if (bp == ap->freelist)
4927dd7cddfSDavid du Colombier break;
4937dd7cddfSDavid du Colombier }
4947dd7cddfSDavid du Colombier if (!ok) {
4957dd7cddfSDavid du Colombier disabled = 1;
4967dd7cddfSDavid du Colombier aerror(ap, "acheck failed");
4977dd7cddfSDavid du Colombier }
4987dd7cddfSDavid du Colombier }
4997dd7cddfSDavid du Colombier
5007dd7cddfSDavid du Colombier void
aprint(ap,ptr,size)5017dd7cddfSDavid du Colombier aprint(ap, ptr, size)
5027dd7cddfSDavid du Colombier register Area *ap;
5037dd7cddfSDavid du Colombier void *ptr;
5047dd7cddfSDavid du Colombier size_t size;
5057dd7cddfSDavid du Colombier {
5067dd7cddfSDavid du Colombier Block *bp;
5077dd7cddfSDavid du Colombier
5087dd7cddfSDavid du Colombier if (!ap)
5097dd7cddfSDavid du Colombier shellf("aprint: null area pointer\n");
5107dd7cddfSDavid du Colombier else if (!(bp = ap->freelist))
5117dd7cddfSDavid du Colombier shellf("aprint: null area freelist\n");
5127dd7cddfSDavid du Colombier else if (bp == &aempty)
5137dd7cddfSDavid du Colombier shellf("aprint: area is empty\n");
5147dd7cddfSDavid du Colombier else {
5157dd7cddfSDavid du Colombier int i;
5167dd7cddfSDavid du Colombier Cell *dp, *fp;
5177dd7cddfSDavid du Colombier Block *bpp;
5187dd7cddfSDavid du Colombier
5197dd7cddfSDavid du Colombier bpp = ap->freelist->prev;
5207dd7cddfSDavid du Colombier for (i = 0; ; i++) {
5217dd7cddfSDavid du Colombier if (ptr) {
5227dd7cddfSDavid du Colombier void *eptr = (void *) (((char *) ptr) + size);
5237dd7cddfSDavid du Colombier /* print block only if it overlaps ptr/size */
5247dd7cddfSDavid du Colombier if (!((ptr >= (void *) bp
5257dd7cddfSDavid du Colombier && ptr <= (void *) bp->last)
5267dd7cddfSDavid du Colombier || (eptr >= (void *) bp
5277dd7cddfSDavid du Colombier && eptr <= (void *) bp->last)))
5287dd7cddfSDavid du Colombier continue;
5297dd7cddfSDavid du Colombier shellf("aprint: overlap of 0x%p .. 0x%p\n",
5307dd7cddfSDavid du Colombier ptr, eptr);
5317dd7cddfSDavid du Colombier }
5327dd7cddfSDavid du Colombier if (bp->prev != bpp || bp->next->prev != bp)
5337dd7cddfSDavid du Colombier shellf(
5347dd7cddfSDavid du Colombier "aprint: BAD prev pointer: bp %p, bp->prev %p, bp->next %p, bpp=%p\n",
5357dd7cddfSDavid du Colombier bp, bp->prev, bp->next, bpp);
5367dd7cddfSDavid du Colombier shellf("aprint: block %2d (p=%p,%p,n=%p): 0x%p .. 0x%p (%ld)\n", i,
5377dd7cddfSDavid du Colombier bp->prev, bp, bp->next,
5387dd7cddfSDavid du Colombier bp->cell, bp->last,
5397dd7cddfSDavid du Colombier (long) ((char *) bp->last - (char *) bp->cell));
5407dd7cddfSDavid du Colombier fp = bp->freelist;
5417dd7cddfSDavid du Colombier if (bp->last <= bp->cell + NOBJECT_FIELDS)
5427dd7cddfSDavid du Colombier shellf(
5437dd7cddfSDavid du Colombier "aprint: BAD bp->last too small: %p <= %p\n",
5447dd7cddfSDavid du Colombier bp->last, bp->cell + NOBJECT_FIELDS);
5457dd7cddfSDavid du Colombier if (bp->freelist < bp->cell + NOBJECT_FIELDS
5467dd7cddfSDavid du Colombier || bp->freelist > bp->last)
5477dd7cddfSDavid du Colombier shellf(
5487dd7cddfSDavid du Colombier "aprint: BAD bp->freelist %p out of range: %p .. %p\n",
5497dd7cddfSDavid du Colombier bp->freelist,
5507dd7cddfSDavid du Colombier bp->cell + NOBJECT_FIELDS, bp->last);
5517dd7cddfSDavid du Colombier for (dp = bp->cell; dp != bp->last ; ) {
5527dd7cddfSDavid du Colombier dp += NOBJECT_FIELDS;
5537dd7cddfSDavid du Colombier shellf(
5547dd7cddfSDavid du Colombier "aprint: 0x%p .. 0x%p (%ld) %s\n",
5557dd7cddfSDavid du Colombier (dp-NOBJECT_FIELDS),
5567dd7cddfSDavid du Colombier (dp-NOBJECT_FIELDS) + (dp-1)->size
5577dd7cddfSDavid du Colombier + NOBJECT_FIELDS,
5587dd7cddfSDavid du Colombier (long) ((dp-1)->size + NOBJECT_FIELDS)
5597dd7cddfSDavid du Colombier * sizeof(Cell),
5607dd7cddfSDavid du Colombier dp == fp ? "free" : "allocated");
5617dd7cddfSDavid du Colombier if ((dp-2)->block != bp)
5627dd7cddfSDavid du Colombier shellf(
5637dd7cddfSDavid du Colombier "aprint: BAD dp->block %p != bp %p\n",
5647dd7cddfSDavid du Colombier (dp-2)->block, bp);
5657dd7cddfSDavid du Colombier if (dp > bp->last)
5667dd7cddfSDavid du Colombier shellf(
5677dd7cddfSDavid du Colombier "aprint: BAD dp gone past block: %p > %p\n",
5687dd7cddfSDavid du Colombier dp, bp->last);
5697dd7cddfSDavid du Colombier if (dp > fp)
5707dd7cddfSDavid du Colombier shellf(
5717dd7cddfSDavid du Colombier "aprint: BAD dp gone past free: %p > %p\n",
5727dd7cddfSDavid du Colombier dp, fp);
5737dd7cddfSDavid du Colombier if (dp == fp) {
5747dd7cddfSDavid du Colombier fp = fp->next;
5757dd7cddfSDavid du Colombier if (fp < dp || fp > bp->last)
5767dd7cddfSDavid du Colombier shellf(
5777dd7cddfSDavid du Colombier "aprint: BAD free object %p out of range: %p .. %p\n",
5787dd7cddfSDavid du Colombier fp,
5797dd7cddfSDavid du Colombier dp, bp->last);
5807dd7cddfSDavid du Colombier }
5817dd7cddfSDavid du Colombier dp += (dp-1)->size;
5827dd7cddfSDavid du Colombier }
5837dd7cddfSDavid du Colombier bpp = bp;
5847dd7cddfSDavid du Colombier bp = bp->next;
5857dd7cddfSDavid du Colombier if (bp == ap->freelist)
5867dd7cddfSDavid du Colombier break;
5877dd7cddfSDavid du Colombier }
5887dd7cddfSDavid du Colombier }
5897dd7cddfSDavid du Colombier }
5907dd7cddfSDavid du Colombier
591*6b6b9ac8SDavid du Colombier #endif
592