Home | History | Annotate | Line # | Download | only in ksh
alloc.c revision 1.5
      1  1.5      agc /*	$NetBSD: alloc.c,v 1.5 2003/06/23 11:38:51 agc Exp $	*/
      2  1.2      tls 
      3  1.1      jtc /*
      4  1.1      jtc  * area-based allocation built on malloc/free
      5  1.1      jtc  */
      6  1.5      agc #include <sys/cdefs.h>
      7  1.5      agc 
      8  1.5      agc #ifndef lint
      9  1.5      agc __RCSID("$NetBSD: alloc.c,v 1.5 2003/06/23 11:38:51 agc Exp $");
     10  1.5      agc #endif
     11  1.5      agc 
     12  1.1      jtc 
     13  1.1      jtc #include "sh.h"
     14  1.4  hubertf 
     15  1.4  hubertf #ifdef TEST_ALLOC
     16  1.4  hubertf # define shellf	printf
     17  1.4  hubertf # ifndef DEBUG_ALLOC
     18  1.4  hubertf #  define DEBUG_ALLOC
     19  1.4  hubertf # endif /* DEBUG_ALLOC */
     20  1.4  hubertf #endif /* TEST_ALLOC */
     21  1.4  hubertf 
     22  1.1      jtc #ifdef MEM_DEBUG
     23  1.1      jtc 
     24  1.4  hubertf /*
     25  1.4  hubertf  * Special versions of alloc routines if doing mem_debug
     26  1.4  hubertf  */
     27  1.4  hubertf Area *
     28  1.4  hubertf _chmem_ainit(ap, file, line)
     29  1.4  hubertf 	Area *ap;
     30  1.4  hubertf 	const char *file;
     31  1.4  hubertf 	int line;
     32  1.4  hubertf {
     33  1.4  hubertf 	ap->freelist = (struct Block *) _chmem_newpool("ainit", (char *) 0, -1,
     34  1.4  hubertf 						file, line);
     35  1.4  hubertf 	if (!ap->freelist)
     36  1.4  hubertf 	    aerror(ap, "ainit failed (ie, newpool)");
     37  1.4  hubertf 	return ap;
     38  1.4  hubertf }
     39  1.4  hubertf 
     40  1.4  hubertf /* free all object in Area */
     41  1.4  hubertf void
     42  1.4  hubertf _chmem_afreeall(ap, file, line)
     43  1.4  hubertf 	Area *ap;
     44  1.4  hubertf 	const char *file;
     45  1.4  hubertf 	int line;
     46  1.4  hubertf {
     47  1.4  hubertf 	_chmem_delpool((Chmem_poolp) ap->freelist, 0, file, line);
     48  1.4  hubertf 	/* Kind of ugly, but it works */
     49  1.4  hubertf 	_chmem_ainit(ap, file, line);
     50  1.4  hubertf }
     51  1.4  hubertf 
     52  1.4  hubertf /* allocate object from Area */
     53  1.4  hubertf void *
     54  1.4  hubertf _chmem_alloc(size, ap, file, line)
     55  1.4  hubertf 	size_t size;
     56  1.4  hubertf 	Area *ap;
     57  1.4  hubertf 	const char *file;
     58  1.4  hubertf 	int line;
     59  1.4  hubertf {
     60  1.4  hubertf 	return _chmem_mallocp((Chmem_poolp) ap->freelist, size, file, line);
     61  1.4  hubertf }
     62  1.4  hubertf 
     63  1.4  hubertf /* change size of object -- like realloc */
     64  1.4  hubertf void *
     65  1.4  hubertf _chmem_aresize(ptr, size, ap, file, line)
     66  1.4  hubertf 	void *ptr;
     67  1.4  hubertf 	size_t size;
     68  1.4  hubertf 	Area *ap;
     69  1.4  hubertf 	const char *file;
     70  1.4  hubertf 	int line;
     71  1.4  hubertf {
     72  1.4  hubertf 	if (!ptr)
     73  1.4  hubertf 		/* Done as realloc(0, size) is not portable */
     74  1.4  hubertf 		return _chmem_mallocp((Chmem_poolp) ap->freelist, size,
     75  1.4  hubertf 					file, line);
     76  1.4  hubertf 	else
     77  1.4  hubertf 		return _chmem_reallocp((Chmem_poolp) ap->freelist, ptr, size,
     78  1.4  hubertf 					file, line);
     79  1.4  hubertf }
     80  1.4  hubertf 
     81  1.4  hubertf void
     82  1.4  hubertf _chmem_afree(ptr, ap, file, line)
     83  1.4  hubertf 	void *ptr;
     84  1.4  hubertf 	Area *ap;
     85  1.4  hubertf 	const char *file;
     86  1.4  hubertf 	int line;
     87  1.4  hubertf {
     88  1.4  hubertf 	return _chmem_freep((Chmem_poolp) ap->freelist, ptr, file, line);
     89  1.4  hubertf }
     90  1.4  hubertf 
     91  1.4  hubertf #else /* MEM_DEBUG */
     92  1.4  hubertf 
     93  1.4  hubertf # if DEBUG_ALLOC
     94  1.4  hubertf void acheck ARGS((Area *ap));
     95  1.4  hubertf #  define ACHECK(ap)	acheck(ap)
     96  1.4  hubertf # else /* DEBUG_ALLOC */
     97  1.4  hubertf #  define ACHECK(ap)
     98  1.4  hubertf # endif /* DEBUG_ALLOC */
     99  1.4  hubertf 
    100  1.4  hubertf #define	ICELLS	200		/* number of Cells in small Block */
    101  1.1      jtc 
    102  1.1      jtc typedef union Cell Cell;
    103  1.1      jtc typedef struct Block Block;
    104  1.1      jtc 
    105  1.1      jtc /*
    106  1.1      jtc  * The Cells in a Block are organized as a set of objects.
    107  1.4  hubertf  * Each object (pointed to by dp) begins with the block it is in
    108  1.4  hubertf  * (dp-2)->block, then has a size in (dp-1)->size, which is
    109  1.1      jtc  * followed with "size" data Cells.  Free objects are
    110  1.1      jtc  * linked together via dp->next.
    111  1.1      jtc  */
    112  1.1      jtc 
    113  1.4  hubertf #define NOBJECT_FIELDS	2	/* the block and size `fields' */
    114  1.4  hubertf 
    115  1.1      jtc union Cell {
    116  1.1      jtc 	size_t	size;
    117  1.1      jtc 	Cell   *next;
    118  1.4  hubertf 	Block  *block;
    119  1.1      jtc 	struct {int _;} junk;	/* alignment */
    120  1.4  hubertf 	double djunk;		/* alignment */
    121  1.1      jtc };
    122  1.1      jtc 
    123  1.1      jtc struct Block {
    124  1.1      jtc 	Block  *next;		/* list of Blocks in Area */
    125  1.4  hubertf 	Block  *prev;		/* previous block in list */
    126  1.1      jtc 	Cell   *freelist;	/* object free list */
    127  1.1      jtc 	Cell   *last;		/* &b.cell[size] */
    128  1.1      jtc 	Cell	cell [1];	/* [size] Cells for allocation */
    129  1.1      jtc };
    130  1.1      jtc 
    131  1.4  hubertf static Block aempty = {&aempty, &aempty, aempty.cell, aempty.cell};
    132  1.4  hubertf 
    133  1.4  hubertf static void ablockfree ARGS((Block *bp, Area *ap));
    134  1.4  hubertf static void *asplit ARGS((Area *ap, Block *bp, Cell *fp, Cell *fpp, int cells));
    135  1.1      jtc 
    136  1.1      jtc /* create empty Area */
    137  1.1      jtc Area *
    138  1.1      jtc ainit(ap)
    139  1.1      jtc 	register Area *ap;
    140  1.1      jtc {
    141  1.1      jtc 	ap->freelist = &aempty;
    142  1.4  hubertf 	ACHECK(ap);
    143  1.1      jtc 	return ap;
    144  1.1      jtc }
    145  1.1      jtc 
    146  1.1      jtc /* free all object in Area */
    147  1.1      jtc void
    148  1.1      jtc afreeall(ap)
    149  1.1      jtc 	register Area *ap;
    150  1.1      jtc {
    151  1.1      jtc 	register Block *bp;
    152  1.1      jtc 	register Block *tmp;
    153  1.1      jtc 
    154  1.4  hubertf 	ACHECK(ap);
    155  1.1      jtc 	bp = ap->freelist;
    156  1.1      jtc 	if (bp != NULL && bp != &aempty) {
    157  1.1      jtc 		do {
    158  1.4  hubertf 			tmp = bp;
    159  1.4  hubertf 			bp = bp->next;
    160  1.4  hubertf 			free((void*)tmp);
    161  1.1      jtc 		} while (bp != ap->freelist);
    162  1.1      jtc 		ap->freelist = &aempty;
    163  1.1      jtc 	}
    164  1.4  hubertf 	ACHECK(ap);
    165  1.1      jtc }
    166  1.1      jtc 
    167  1.1      jtc /* allocate object from Area */
    168  1.1      jtc void *
    169  1.1      jtc alloc(size, ap)
    170  1.1      jtc 	size_t size;
    171  1.1      jtc 	register Area *ap;
    172  1.1      jtc {
    173  1.4  hubertf 	int cells, acells;
    174  1.4  hubertf 	Block *bp = 0;
    175  1.4  hubertf 	Cell *fp = 0, *fpp = 0;
    176  1.1      jtc 
    177  1.4  hubertf 	ACHECK(ap);
    178  1.4  hubertf 	if (size <= 0)
    179  1.1      jtc 		aerror(ap, "allocate bad size");
    180  1.4  hubertf 	cells = (unsigned)(size + sizeof(Cell) - 1) / sizeof(Cell);
    181  1.4  hubertf 
    182  1.4  hubertf 	/* allocate at least this many cells */
    183  1.4  hubertf 	acells = cells + NOBJECT_FIELDS;
    184  1.1      jtc 
    185  1.4  hubertf 	/*
    186  1.4  hubertf 	 * Only attempt to track small objects - let malloc deal
    187  1.4  hubertf 	 * with larger objects. (this way we don't have to deal with
    188  1.4  hubertf 	 * coalescing memory, or with releasing it to the system)
    189  1.4  hubertf 	 */
    190  1.4  hubertf 	if (cells <= ICELLS) {
    191  1.4  hubertf 		/* find free Cell large enough */
    192  1.4  hubertf 		for (bp = ap->freelist; ; bp = bp->next) {
    193  1.4  hubertf 			for (fpp = NULL, fp = bp->freelist;
    194  1.4  hubertf 			     fp != bp->last; fpp = fp, fp = fp->next)
    195  1.4  hubertf 			{
    196  1.4  hubertf 				if ((fp-1)->size >= cells)
    197  1.4  hubertf 					goto Found;
    198  1.1      jtc 			}
    199  1.4  hubertf 			/* wrapped around Block list, create new Block */
    200  1.4  hubertf 			if (bp->next == ap->freelist) {
    201  1.4  hubertf 				bp = 0;
    202  1.4  hubertf 				break;
    203  1.1      jtc 			}
    204  1.1      jtc 		}
    205  1.4  hubertf 		/* Not much free space left?  Allocate a big object this time */
    206  1.4  hubertf 		acells += ICELLS;
    207  1.4  hubertf 	}
    208  1.4  hubertf 	if (bp == 0) {
    209  1.4  hubertf 		bp = (Block*) malloc(offsetof(Block, cell[acells]));
    210  1.4  hubertf 		if (bp == NULL)
    211  1.4  hubertf 			aerror(ap, "cannot allocate");
    212  1.4  hubertf 		if (ap->freelist == &aempty) {
    213  1.4  hubertf 			ap->freelist = bp->next = bp->prev = bp;
    214  1.4  hubertf 		} else {
    215  1.4  hubertf 			bp->next = ap->freelist->next;
    216  1.4  hubertf 			ap->freelist->next->prev = bp;
    217  1.4  hubertf 			ap->freelist->next = bp;
    218  1.4  hubertf 			bp->prev = ap->freelist;
    219  1.4  hubertf 		}
    220  1.4  hubertf 		bp->last = bp->cell + acells;
    221  1.4  hubertf 		/* initial free list */
    222  1.4  hubertf 		fp = bp->freelist = bp->cell + NOBJECT_FIELDS;
    223  1.4  hubertf 		(fp-1)->size = acells - NOBJECT_FIELDS;
    224  1.4  hubertf 		(fp-2)->block = bp;
    225  1.4  hubertf 		fp->next = bp->last;
    226  1.4  hubertf 		fpp = NULL;
    227  1.1      jtc 	}
    228  1.4  hubertf 
    229  1.1      jtc   Found:
    230  1.4  hubertf 	return asplit(ap, bp, fp, fpp, cells);
    231  1.4  hubertf }
    232  1.4  hubertf 
    233  1.4  hubertf /* Do the work of splitting an object into allocated and (possibly) unallocated
    234  1.4  hubertf  * objects.  Returns the `allocated' object.
    235  1.4  hubertf  */
    236  1.4  hubertf static void *
    237  1.4  hubertf asplit(ap, bp, fp, fpp, cells)
    238  1.4  hubertf 	Area *ap;
    239  1.4  hubertf 	Block *bp;
    240  1.4  hubertf 	Cell *fp;
    241  1.4  hubertf 	Cell *fpp;
    242  1.4  hubertf 	int cells;
    243  1.4  hubertf {
    244  1.4  hubertf 	Cell *dp = fp;	/* allocated object */
    245  1.4  hubertf 	int split = (fp-1)->size - cells;
    246  1.4  hubertf 
    247  1.4  hubertf 	ACHECK(ap);
    248  1.1      jtc 	if (split < 0)
    249  1.1      jtc 		aerror(ap, "allocated object too small");
    250  1.4  hubertf 	if (split <= NOBJECT_FIELDS) {	/* allocate all */
    251  1.1      jtc 		fp = fp->next;
    252  1.1      jtc 	} else {		/* allocate head, free tail */
    253  1.4  hubertf 		Cell *next = fp->next; /* needed, as cells may be 0 */
    254  1.4  hubertf 		ap->freelist = bp; /* next time, start looking for space here */
    255  1.1      jtc 		(fp-1)->size = cells;
    256  1.4  hubertf 		fp += cells + NOBJECT_FIELDS;
    257  1.4  hubertf 		(fp-1)->size = split - NOBJECT_FIELDS;
    258  1.4  hubertf 		(fp-2)->block = bp;
    259  1.4  hubertf 		fp->next = next;
    260  1.1      jtc 	}
    261  1.1      jtc 	if (fpp == NULL)
    262  1.1      jtc 		bp->freelist = fp;
    263  1.1      jtc 	else
    264  1.1      jtc 		fpp->next = fp;
    265  1.4  hubertf 	ACHECK(ap);
    266  1.1      jtc 	return (void*) dp;
    267  1.1      jtc }
    268  1.1      jtc 
    269  1.1      jtc /* change size of object -- like realloc */
    270  1.1      jtc void *
    271  1.1      jtc aresize(ptr, size, ap)
    272  1.1      jtc 	register void *ptr;
    273  1.1      jtc 	size_t size;
    274  1.1      jtc 	Area *ap;
    275  1.1      jtc {
    276  1.1      jtc 	int cells;
    277  1.4  hubertf 	Cell *dp = (Cell*) ptr;
    278  1.4  hubertf 	int oldcells = dp ? (dp-1)->size : 0;
    279  1.1      jtc 
    280  1.4  hubertf 	ACHECK(ap);
    281  1.4  hubertf 	if (size <= 0)
    282  1.1      jtc 		aerror(ap, "allocate bad size");
    283  1.4  hubertf 	/* New size (in cells) */
    284  1.1      jtc 	cells = (unsigned)(size - 1) / sizeof(Cell) + 1;
    285  1.1      jtc 
    286  1.4  hubertf 	/* Is this a large object?  If so, let malloc deal with it
    287  1.4  hubertf 	 * directly (unless we are crossing the ICELLS border, in
    288  1.4  hubertf 	 * which case the alloc/free below handles it - this should
    289  1.4  hubertf 	 * cut down on fragmentation, and will also keep the code
    290  1.4  hubertf 	 * working (as it assumes size < ICELLS means it is not
    291  1.4  hubertf 	 * a `large object').
    292  1.4  hubertf 	 */
    293  1.4  hubertf 	if (oldcells > ICELLS && cells > ICELLS) {
    294  1.4  hubertf 		Block *bp = (dp-2)->block;
    295  1.4  hubertf 		Block *nbp;
    296  1.4  hubertf 		/* Saved in case realloc fails.. */
    297  1.4  hubertf 		Block *next = bp->next, *prev = bp->prev;
    298  1.4  hubertf 
    299  1.4  hubertf 		if (bp->freelist != bp->last)
    300  1.4  hubertf 			aerror(ap, "allocation resizing free pointer");
    301  1.4  hubertf 		nbp = realloc((void *) bp,
    302  1.4  hubertf 			      offsetof(Block, cell[cells + NOBJECT_FIELDS]));
    303  1.4  hubertf 		if (!nbp) {
    304  1.4  hubertf 			/* Have to clean up... */
    305  1.4  hubertf 			/* NOTE: If this code changes, similar changes may be
    306  1.4  hubertf 			 * needed in ablockfree().
    307  1.4  hubertf 			 */
    308  1.4  hubertf 			if (next == bp) /* only block */
    309  1.4  hubertf 				ap->freelist = &aempty;
    310  1.4  hubertf 			else {
    311  1.4  hubertf 				next->prev = prev;
    312  1.4  hubertf 				prev->next = next;
    313  1.4  hubertf 				if (ap->freelist == bp)
    314  1.4  hubertf 					ap->freelist = next;
    315  1.4  hubertf 			}
    316  1.4  hubertf 			aerror(ap, "cannot re-allocate");
    317  1.4  hubertf 		}
    318  1.4  hubertf 		/* If location changed, keep pointers straight... */
    319  1.4  hubertf 		if (nbp != bp) {
    320  1.4  hubertf 			if (next == bp) /* only one block */
    321  1.4  hubertf 				nbp->next = nbp->prev = nbp;
    322  1.4  hubertf 			else {
    323  1.4  hubertf 				next->prev = nbp;
    324  1.4  hubertf 				prev->next = nbp;
    325  1.4  hubertf 			}
    326  1.4  hubertf 			if (ap->freelist == bp)
    327  1.4  hubertf 				ap->freelist = nbp;
    328  1.4  hubertf 			dp = nbp->cell + NOBJECT_FIELDS;
    329  1.4  hubertf 			(dp-2)->block = nbp;
    330  1.1      jtc 		}
    331  1.4  hubertf 		(dp-1)->size = cells;
    332  1.4  hubertf 		nbp->last = nbp->cell + cells + NOBJECT_FIELDS;
    333  1.4  hubertf 		nbp->freelist = nbp->last;
    334  1.4  hubertf 
    335  1.4  hubertf 		ACHECK(ap);
    336  1.4  hubertf 		return (void*) dp;
    337  1.4  hubertf 	}
    338  1.4  hubertf 
    339  1.4  hubertf 	/* Check if we can just grow this cell
    340  1.4  hubertf 	 * (need to check that cells < ICELLS so we don't make an
    341  1.4  hubertf 	 * object a `large' - that would mess everything up).
    342  1.4  hubertf 	 */
    343  1.4  hubertf 	if (dp && cells > oldcells && cells <= ICELLS) {
    344  1.4  hubertf 		Cell *fp, *fpp;
    345  1.4  hubertf 		Block *bp = (dp-2)->block;
    346  1.4  hubertf 		int need = cells - oldcells - NOBJECT_FIELDS;
    347  1.4  hubertf 
    348  1.4  hubertf 		/* XXX if we had a flag in an object indicating
    349  1.4  hubertf 		 * if the object was free/allocated, we could
    350  1.4  hubertf 		 * avoid this loop (perhaps)
    351  1.4  hubertf 		 */
    352  1.4  hubertf 		for (fpp = NULL, fp = bp->freelist;
    353  1.4  hubertf 		     fp != bp->last
    354  1.4  hubertf 		     && dp + oldcells + NOBJECT_FIELDS <= fp
    355  1.4  hubertf 		     ; fpp = fp, fp = fp->next)
    356  1.4  hubertf 		{
    357  1.4  hubertf 			if (dp + oldcells + NOBJECT_FIELDS == fp
    358  1.4  hubertf 			    && (fp-1)->size >= need)
    359  1.4  hubertf 			{
    360  1.4  hubertf 				Cell *np = asplit(ap, bp, fp, fpp, need);
    361  1.4  hubertf 				/* May get more than we need here */
    362  1.4  hubertf 				(dp-1)->size += (np-1)->size + NOBJECT_FIELDS;
    363  1.4  hubertf 				ACHECK(ap);
    364  1.4  hubertf 				return ptr;
    365  1.4  hubertf 			}
    366  1.4  hubertf 		}
    367  1.4  hubertf 	}
    368  1.4  hubertf 
    369  1.4  hubertf 	/* Check if we can just shrink this cell
    370  1.4  hubertf 	 * (if oldcells > ICELLS, this is a large object and we leave
    371  1.4  hubertf 	 * it to malloc...)
    372  1.4  hubertf 	 * Note: this also handles cells == oldcells (a no-op).
    373  1.4  hubertf 	 */
    374  1.4  hubertf 	if (dp && cells <= oldcells && oldcells <= ICELLS) {
    375  1.1      jtc 		int split;
    376  1.1      jtc 
    377  1.4  hubertf 		split = oldcells - cells;
    378  1.4  hubertf 		if (split <= NOBJECT_FIELDS) /* cannot split */
    379  1.1      jtc 			;
    380  1.1      jtc 		else {		/* shrink head, free tail */
    381  1.4  hubertf 			Block *bp = (dp-2)->block;
    382  1.4  hubertf 
    383  1.1      jtc 			(dp-1)->size = cells;
    384  1.4  hubertf 			dp += cells + NOBJECT_FIELDS;
    385  1.4  hubertf 			(dp-1)->size = split - NOBJECT_FIELDS;
    386  1.4  hubertf 			(dp-2)->block = bp;
    387  1.1      jtc 			afree((void*)dp, ap);
    388  1.1      jtc 		}
    389  1.4  hubertf 		/* ACHECK() done in afree() */
    390  1.4  hubertf 		return ptr;
    391  1.1      jtc 	}
    392  1.4  hubertf 
    393  1.4  hubertf 	/* Have to do it the hard way... */
    394  1.4  hubertf 	ptr = alloc(size, ap);
    395  1.4  hubertf 	if (dp != NULL) {
    396  1.4  hubertf 		size_t s = (dp-1)->size * sizeof(Cell);
    397  1.4  hubertf 		if (s > size)
    398  1.4  hubertf 			s = size;
    399  1.4  hubertf 		memcpy(ptr, dp, s);
    400  1.4  hubertf 		afree((void *) dp, ap);
    401  1.4  hubertf 	}
    402  1.4  hubertf 	/* ACHECK() done in alloc()/afree() */
    403  1.4  hubertf 	return ptr;
    404  1.1      jtc }
    405  1.1      jtc 
    406  1.1      jtc void
    407  1.1      jtc afree(ptr, ap)
    408  1.1      jtc 	void *ptr;
    409  1.1      jtc 	register Area *ap;
    410  1.1      jtc {
    411  1.1      jtc 	register Block *bp;
    412  1.1      jtc 	register Cell *fp, *fpp;
    413  1.1      jtc 	register Cell *dp = (Cell*)ptr;
    414  1.1      jtc 
    415  1.4  hubertf 	ACHECK(ap);
    416  1.4  hubertf 	if (ptr == 0)
    417  1.4  hubertf 		aerror(ap, "freeing null pointer");
    418  1.4  hubertf 	bp = (dp-2)->block;
    419  1.4  hubertf 
    420  1.4  hubertf 	/* If this is a large object, just free it up... */
    421  1.4  hubertf 	/* Release object... */
    422  1.4  hubertf 	if ((dp-1)->size > ICELLS) {
    423  1.4  hubertf 		ablockfree(bp, ap);
    424  1.4  hubertf 		ACHECK(ap);
    425  1.4  hubertf 		return;
    426  1.1      jtc 	}
    427  1.1      jtc 
    428  1.4  hubertf 	if (dp < &bp->cell[NOBJECT_FIELDS] || dp >= bp->last)
    429  1.4  hubertf 		aerror(ap, "freeing memory outside of block (corrupted?)");
    430  1.4  hubertf 
    431  1.1      jtc 	/* find position in free list */
    432  1.4  hubertf 	/* XXX if we had prev/next pointers for objects, this loop could go */
    433  1.4  hubertf 	for (fpp = NULL, fp = bp->freelist; fp < dp; fpp = fp, fp = fp->next)
    434  1.1      jtc 		;
    435  1.1      jtc 
    436  1.4  hubertf 	if (fp == dp)
    437  1.1      jtc 		aerror(ap, "freeing free object");
    438  1.1      jtc 
    439  1.1      jtc 	/* join object with next */
    440  1.4  hubertf 	if (dp + (dp-1)->size == fp-NOBJECT_FIELDS) { /* adjacent */
    441  1.4  hubertf 		(dp-1)->size += (fp-1)->size + NOBJECT_FIELDS;
    442  1.1      jtc 		dp->next = fp->next;
    443  1.1      jtc 	} else			/* non-adjacent */
    444  1.1      jtc 		dp->next = fp;
    445  1.1      jtc 
    446  1.1      jtc 	/* join previous with object */
    447  1.1      jtc 	if (fpp == NULL)
    448  1.1      jtc 		bp->freelist = dp;
    449  1.4  hubertf 	else if (fpp + (fpp-1)->size == dp-NOBJECT_FIELDS) { /* adjacent */
    450  1.4  hubertf 		(fpp-1)->size += (dp-1)->size + NOBJECT_FIELDS;
    451  1.1      jtc 		fpp->next = dp->next;
    452  1.1      jtc 	} else			/* non-adjacent */
    453  1.1      jtc 		fpp->next = dp;
    454  1.4  hubertf 
    455  1.4  hubertf 	/* If whole block is free (and we have some other blocks
    456  1.4  hubertf 	 * around), release this block back to the system...
    457  1.4  hubertf 	 */
    458  1.4  hubertf 	if (bp->next != bp && bp->freelist == bp->cell + NOBJECT_FIELDS
    459  1.4  hubertf 	    && bp->freelist + (bp->freelist-1)->size == bp->last
    460  1.4  hubertf 	    /* XXX and the other block has some free memory? */
    461  1.4  hubertf 	    )
    462  1.4  hubertf 		ablockfree(bp, ap);
    463  1.4  hubertf 	ACHECK(ap);
    464  1.4  hubertf }
    465  1.4  hubertf 
    466  1.4  hubertf static void
    467  1.4  hubertf ablockfree(bp, ap)
    468  1.4  hubertf 	Block *bp;
    469  1.4  hubertf 	Area *ap;
    470  1.4  hubertf {
    471  1.4  hubertf 	/* NOTE: If this code changes, similar changes may be
    472  1.4  hubertf 	 * needed in alloc() (where realloc fails).
    473  1.4  hubertf 	 */
    474  1.4  hubertf 
    475  1.4  hubertf 	if (bp->next == bp) /* only block */
    476  1.4  hubertf 		ap->freelist = &aempty;
    477  1.4  hubertf 	else {
    478  1.4  hubertf 		bp->next->prev = bp->prev;
    479  1.4  hubertf 		bp->prev->next = bp->next;
    480  1.4  hubertf 		if (ap->freelist == bp)
    481  1.4  hubertf 			ap->freelist = bp->next;
    482  1.4  hubertf 	}
    483  1.4  hubertf 	free((void*) bp);
    484  1.4  hubertf }
    485  1.4  hubertf 
    486  1.4  hubertf # if DEBUG_ALLOC
    487  1.4  hubertf void
    488  1.4  hubertf acheck(ap)
    489  1.4  hubertf 	Area *ap;
    490  1.4  hubertf {
    491  1.4  hubertf 	Block *bp, *bpp;
    492  1.4  hubertf 	Cell *dp, *dptmp, *fp;
    493  1.4  hubertf 	int ok = 1;
    494  1.4  hubertf 	int isfree;
    495  1.4  hubertf 	static int disabled;
    496  1.4  hubertf 
    497  1.4  hubertf 	if (disabled)
    498  1.4  hubertf 		return;
    499  1.4  hubertf 
    500  1.4  hubertf 	if (!ap) {
    501  1.4  hubertf 		disabled = 1;
    502  1.4  hubertf 		aerror(ap, "acheck: null area pointer");
    503  1.4  hubertf 	}
    504  1.4  hubertf 
    505  1.4  hubertf 	bp = ap->freelist;
    506  1.4  hubertf 	if (!bp) {
    507  1.4  hubertf 		disabled = 1;
    508  1.4  hubertf 		aerror(ap, "acheck: null area freelist");
    509  1.4  hubertf 	}
    510  1.4  hubertf 
    511  1.4  hubertf 	/* Nothing to check... */
    512  1.4  hubertf 	if (bp == &aempty)
    513  1.4  hubertf 		return;
    514  1.4  hubertf 
    515  1.4  hubertf 	bpp = ap->freelist->prev;
    516  1.4  hubertf 	while (1) {
    517  1.4  hubertf 		if (bp->prev != bpp) {
    518  1.4  hubertf 			shellf("acheck: bp->prev != previous\n");
    519  1.4  hubertf 			ok = 0;
    520  1.4  hubertf 		}
    521  1.4  hubertf 		fp = bp->freelist;
    522  1.4  hubertf 		for (dp = &bp->cell[NOBJECT_FIELDS]; dp != bp->last; ) {
    523  1.4  hubertf 			if ((dp-2)->block != bp) {
    524  1.4  hubertf 				shellf("acheck: fragment's block is wrong\n");
    525  1.4  hubertf 				ok = 0;
    526  1.4  hubertf 			}
    527  1.4  hubertf 			isfree = dp == fp;
    528  1.4  hubertf 			if ((dp-1)->size == 0 && isfree) {
    529  1.4  hubertf 				shellf("acheck: 0 size frag\n");
    530  1.4  hubertf 				ok = 0;
    531  1.4  hubertf 			}
    532  1.4  hubertf 			if ((dp-1)->size > ICELLS
    533  1.4  hubertf 			    && !isfree
    534  1.4  hubertf 			    && (dp != &bp->cell[NOBJECT_FIELDS]
    535  1.4  hubertf 				|| dp + (dp-1)->size != bp->last))
    536  1.4  hubertf 			{
    537  1.4  hubertf 				shellf("acheck: big cell doesn't make up whole block\n");
    538  1.4  hubertf 				ok = 0;
    539  1.4  hubertf 			}
    540  1.4  hubertf 			if (isfree) {
    541  1.4  hubertf 				if (dp->next <= dp) {
    542  1.4  hubertf 					shellf("acheck: free fragment's next <= self\n");
    543  1.4  hubertf 					ok = 0;
    544  1.4  hubertf 				}
    545  1.4  hubertf 				if (dp->next > bp->last) {
    546  1.4  hubertf 					shellf("acheck: free fragment's next > last\n");
    547  1.4  hubertf 					ok = 0;
    548  1.4  hubertf 				}
    549  1.4  hubertf 				fp = dp->next;
    550  1.4  hubertf 			}
    551  1.4  hubertf 			dptmp = dp + (dp-1)->size;
    552  1.4  hubertf 			if (dptmp > bp->last) {
    553  1.4  hubertf 				shellf("acheck: next frag out of range\n");
    554  1.4  hubertf 				ok = 0;
    555  1.4  hubertf 				break;
    556  1.4  hubertf 			} else if (dptmp != bp->last) {
    557  1.4  hubertf 				dptmp += NOBJECT_FIELDS;
    558  1.4  hubertf 				if (dptmp > bp->last) {
    559  1.4  hubertf 					shellf("acheck: next frag just out of range\n");
    560  1.4  hubertf 					ok = 0;
    561  1.4  hubertf 					break;
    562  1.4  hubertf 				}
    563  1.4  hubertf 			}
    564  1.4  hubertf 			if (isfree && dptmp == fp && dptmp != bp->last) {
    565  1.4  hubertf 				shellf("acheck: adjacent free frags\n");
    566  1.4  hubertf 				ok = 0;
    567  1.4  hubertf 			} else if (dptmp > fp) {
    568  1.4  hubertf 				shellf("acheck: free frag list messed up\n");
    569  1.4  hubertf 				ok = 0;
    570  1.4  hubertf 			}
    571  1.4  hubertf 			dp = dptmp;
    572  1.4  hubertf 		}
    573  1.4  hubertf 		bpp = bp;
    574  1.4  hubertf 		bp = bp->next;
    575  1.4  hubertf 		if (bp == ap->freelist)
    576  1.4  hubertf 			break;
    577  1.4  hubertf 	}
    578  1.4  hubertf 	if (!ok) {
    579  1.4  hubertf 		disabled = 1;
    580  1.4  hubertf 		aerror(ap, "acheck failed");
    581  1.4  hubertf 	}
    582  1.1      jtc }
    583  1.1      jtc 
    584  1.1      jtc void
    585  1.1      jtc aprint(ap, ptr, size)
    586  1.1      jtc 	register Area *ap;
    587  1.1      jtc 	void *ptr;
    588  1.1      jtc 	size_t size;
    589  1.1      jtc {
    590  1.1      jtc 	Block *bp;
    591  1.1      jtc 
    592  1.1      jtc 	if (!ap)
    593  1.1      jtc 		shellf("aprint: null area pointer\n");
    594  1.1      jtc 	else if (!(bp = ap->freelist))
    595  1.1      jtc 		shellf("aprint: null area freelist\n");
    596  1.1      jtc 	else if (bp == &aempty)
    597  1.1      jtc 		shellf("aprint: area is empty\n");
    598  1.1      jtc 	else {
    599  1.1      jtc 		int i;
    600  1.4  hubertf 		Cell *dp, *fp;
    601  1.4  hubertf 		Block *bpp;
    602  1.1      jtc 
    603  1.4  hubertf 		bpp = ap->freelist->prev;
    604  1.4  hubertf 		for (i = 0; ; i++) {
    605  1.1      jtc 			if (ptr) {
    606  1.1      jtc 				void *eptr = (void *) (((char *) ptr) + size);
    607  1.1      jtc 				/* print block only if it overlaps ptr/size */
    608  1.1      jtc 				if (!((ptr >= (void *) bp
    609  1.1      jtc 				       && ptr <= (void *) bp->last)
    610  1.1      jtc 				      || (eptr >= (void *) bp
    611  1.1      jtc 				         && eptr <= (void *) bp->last)))
    612  1.1      jtc 					continue;
    613  1.1      jtc 				shellf("aprint: overlap of 0x%p .. 0x%p\n",
    614  1.1      jtc 					ptr, eptr);
    615  1.1      jtc 			}
    616  1.4  hubertf 			if (bp->prev != bpp || bp->next->prev != bp)
    617  1.4  hubertf 				shellf(
    618  1.4  hubertf 	"aprint: BAD prev pointer: bp %p, bp->prev %p, bp->next %p, bpp=%p\n",
    619  1.4  hubertf 					bp, bp->prev, bp->next, bpp);
    620  1.4  hubertf 			shellf("aprint: block %2d (p=%p,%p,n=%p): 0x%p .. 0x%p (%ld)\n", i,
    621  1.4  hubertf 				bp->prev, bp, bp->next,
    622  1.1      jtc 				bp->cell, bp->last,
    623  1.4  hubertf 				(long) ((char *) bp->last - (char *) bp->cell));
    624  1.4  hubertf 			fp = bp->freelist;
    625  1.4  hubertf 			if (bp->last <= bp->cell + NOBJECT_FIELDS)
    626  1.1      jtc 				shellf(
    627  1.4  hubertf 			"aprint: BAD bp->last too small: %p <= %p\n",
    628  1.4  hubertf 					bp->last, bp->cell + NOBJECT_FIELDS);
    629  1.4  hubertf 			if (bp->freelist < bp->cell + NOBJECT_FIELDS
    630  1.4  hubertf 			    || bp->freelist > bp->last)
    631  1.4  hubertf 				shellf(
    632  1.4  hubertf 			"aprint: BAD bp->freelist %p out of range: %p .. %p\n",
    633  1.4  hubertf 					bp->freelist,
    634  1.4  hubertf 					bp->cell + NOBJECT_FIELDS, bp->last);
    635  1.4  hubertf 			for (dp = bp->cell; dp != bp->last ; ) {
    636  1.4  hubertf 				dp += NOBJECT_FIELDS;
    637  1.4  hubertf 				shellf(
    638  1.4  hubertf 				    "aprint:   0x%p .. 0x%p (%ld) %s\n",
    639  1.4  hubertf 					(dp-NOBJECT_FIELDS),
    640  1.4  hubertf 					(dp-NOBJECT_FIELDS) + (dp-1)->size
    641  1.4  hubertf 						+ NOBJECT_FIELDS,
    642  1.4  hubertf 					(long) ((dp-1)->size + NOBJECT_FIELDS)
    643  1.4  hubertf 						* sizeof(Cell),
    644  1.4  hubertf 					dp == fp ? "free" : "allocated");
    645  1.4  hubertf 				if ((dp-2)->block != bp)
    646  1.4  hubertf 					shellf(
    647  1.4  hubertf 					"aprint: BAD dp->block %p != bp %p\n",
    648  1.4  hubertf 						(dp-2)->block, bp);
    649  1.4  hubertf 				if (dp > bp->last)
    650  1.4  hubertf 					shellf(
    651  1.4  hubertf 				"aprint: BAD dp gone past block: %p > %p\n",
    652  1.4  hubertf 						dp, bp->last);
    653  1.4  hubertf 				if (dp > fp)
    654  1.4  hubertf 					shellf(
    655  1.4  hubertf 				"aprint: BAD dp gone past free: %p > %p\n",
    656  1.4  hubertf 						dp, fp);
    657  1.4  hubertf 				if (dp == fp) {
    658  1.4  hubertf 					fp = fp->next;
    659  1.4  hubertf 					if (fp < dp || fp > bp->last)
    660  1.4  hubertf 						shellf(
    661  1.4  hubertf 			"aprint: BAD free object %p out of range: %p .. %p\n",
    662  1.4  hubertf 							fp,
    663  1.4  hubertf 							dp, bp->last);
    664  1.4  hubertf 				}
    665  1.4  hubertf 				dp += (dp-1)->size;
    666  1.4  hubertf 			}
    667  1.4  hubertf 			bpp = bp;
    668  1.4  hubertf 			bp = bp->next;
    669  1.4  hubertf 			if (bp == ap->freelist)
    670  1.4  hubertf 				break;
    671  1.1      jtc 		}
    672  1.1      jtc 	}
    673  1.1      jtc }
    674  1.4  hubertf # endif /* DEBUG_ALLOC */
    675  1.1      jtc 
    676  1.4  hubertf # ifdef TEST_ALLOC
    677  1.1      jtc 
    678  1.1      jtc Area a;
    679  1.4  hubertf FILE *myout;
    680  1.1      jtc 
    681  1.4  hubertf int
    682  1.4  hubertf main(int argc, char **argv)
    683  1.4  hubertf {
    684  1.4  hubertf 	char buf[1024];
    685  1.4  hubertf 	struct info {
    686  1.4  hubertf 		int size;
    687  1.4  hubertf 		void *value;
    688  1.4  hubertf 	};
    689  1.4  hubertf 	struct info info[1024 * 2];
    690  1.4  hubertf 	int size, ident;
    691  1.4  hubertf 	int lineno = 0;
    692  1.1      jtc 
    693  1.4  hubertf 	myout = stdout;
    694  1.1      jtc 	ainit(&a);
    695  1.4  hubertf 	while (fgets(buf, sizeof(buf), stdin)) {
    696  1.4  hubertf 		lineno++;
    697  1.4  hubertf 		if (buf[0] == '\n' || buf[0] == '#')
    698  1.4  hubertf 			continue;
    699  1.4  hubertf 		if (sscanf(buf, " alloc %d = i%d", &size, &ident) == 2) {
    700  1.4  hubertf 			if (ident < 0 || ident > NELEM(info)) {
    701  1.4  hubertf 				fprintf(stderr, "bad ident (%d) on line %d\n",
    702  1.4  hubertf 					ident, lineno);
    703  1.4  hubertf 				exit(1);
    704  1.4  hubertf 			}
    705  1.4  hubertf 			info[ident].value = alloc(info[ident].size = size, &a);
    706  1.4  hubertf 			printf("%p = alloc(%d) [%d,i%d]\n",
    707  1.4  hubertf 				info[ident].value, info[ident].size,
    708  1.4  hubertf 				lineno, ident);
    709  1.4  hubertf 			memset(info[ident].value, 1, size);
    710  1.4  hubertf 			continue;
    711  1.4  hubertf 		}
    712  1.4  hubertf 		if (sscanf(buf, " afree i%d", &ident) == 1) {
    713  1.4  hubertf 			if (ident < 0 || ident > NELEM(info)) {
    714  1.4  hubertf 				fprintf(stderr, "bad ident (%d) on line %d\n",
    715  1.4  hubertf 					ident, lineno);
    716  1.4  hubertf 				exit(1);
    717  1.4  hubertf 			}
    718  1.4  hubertf 			afree(info[ident].value, &a);
    719  1.4  hubertf 			printf("afree(%p) [%d,i%d]\n", info[ident].value,
    720  1.4  hubertf 				lineno, ident);
    721  1.4  hubertf 			continue;
    722  1.4  hubertf 		}
    723  1.4  hubertf 		if (sscanf(buf, " aresize i%d , %d", &ident, &size) == 2) {
    724  1.4  hubertf 			void *value;
    725  1.4  hubertf 			if (ident < 0 || ident > NELEM(info)) {
    726  1.4  hubertf 				fprintf(stderr, "bad ident (%d) on line %d\n",
    727  1.4  hubertf 					ident, lineno);
    728  1.4  hubertf 				exit(1);
    729  1.4  hubertf 			}
    730  1.4  hubertf 			value = info[ident].value;
    731  1.4  hubertf 			info[ident].value = aresize(value,
    732  1.4  hubertf 						    info[ident].size = size,
    733  1.4  hubertf 						    &a);
    734  1.4  hubertf 			printf("%p = aresize(%p, %d) [%d,i%d]\n",
    735  1.4  hubertf 				info[ident].value, value, info[ident].size,
    736  1.4  hubertf 				lineno, ident);
    737  1.4  hubertf 			memset(info[ident].value, 1, size);
    738  1.4  hubertf 			continue;
    739  1.4  hubertf 		}
    740  1.4  hubertf 		if (sscanf(buf, " aprint i%d , %d", &ident, &size) == 2) {
    741  1.4  hubertf 			if (ident < 0 || ident > NELEM(info)) {
    742  1.4  hubertf 				fprintf(stderr, "bad ident (%d) on line %d\n",
    743  1.4  hubertf 					ident, lineno);
    744  1.4  hubertf 				exit(1);
    745  1.4  hubertf 			}
    746  1.4  hubertf 			printf("aprint(%p, %d) [%d,i%d]\n",
    747  1.4  hubertf 				info[ident].value, size, lineno, ident);
    748  1.4  hubertf 			aprint(&a, info[ident].value, size);
    749  1.4  hubertf 			continue;
    750  1.4  hubertf 		}
    751  1.4  hubertf 		if (sscanf(buf, " aprint %d", &ident) == 1) {
    752  1.4  hubertf 			if (ident < 0 || ident > NELEM(info)) {
    753  1.4  hubertf 				fprintf(stderr, "bad ident (%d) on line %d\n",
    754  1.4  hubertf 					ident, lineno);
    755  1.4  hubertf 				exit(1);
    756  1.4  hubertf 			}
    757  1.4  hubertf 			printf("aprint(0, 0) [%d]\n", lineno);
    758  1.4  hubertf 			aprint(&a, 0, 0);
    759  1.4  hubertf 			continue;
    760  1.4  hubertf 		}
    761  1.4  hubertf 		if (sscanf(buf, " afreeall %d", &ident) == 1) {
    762  1.4  hubertf 			printf("afreeall() [%d]\n", lineno);
    763  1.4  hubertf 			afreeall(&a);
    764  1.4  hubertf 			memset(info, 0, sizeof(info));
    765  1.4  hubertf 			continue;
    766  1.4  hubertf 		}
    767  1.4  hubertf 		fprintf(stderr, "unrecognized line (line %d)\n",
    768  1.4  hubertf 			lineno);
    769  1.4  hubertf 		exit(1);
    770  1.4  hubertf 	}
    771  1.1      jtc 	return 0;
    772  1.1      jtc }
    773  1.1      jtc 
    774  1.4  hubertf void
    775  1.4  hubertf aerror(Area *ap, const char *msg)
    776  1.4  hubertf {
    777  1.4  hubertf 	printf("aerror: %s\n", msg);
    778  1.4  hubertf 	fflush(stdout);
    779  1.1      jtc 	abort();
    780  1.1      jtc }
    781  1.1      jtc 
    782  1.4  hubertf # endif /* TEST_ALLOC */
    783  1.1      jtc 
    784  1.4  hubertf #endif /* MEM_DEBUG */
    785