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