Home | History | Annotate | Line # | Download | only in ksh
alloc.c revision 1.3
      1 /*	$NetBSD: alloc.c,v 1.3 1997/07/20 17:41:59 christos Exp $	*/
      2 
      3 /*
      4  * area-based allocation built on malloc/free
      5  */
      6 
      7 #include "sh.h"
      8 #ifdef MEM_DEBUG
      9 # undef alloc
     10 # undef aresize
     11 # undef afree
     12 #endif /* MEM_DEBUG */
     13 
     14 #define	ICELLS	100		/* number of Cells in small Block */
     15 
     16 typedef union Cell Cell;
     17 typedef struct Block Block;
     18 
     19 /*
     20  * The Cells in a Block are organized as a set of objects.
     21  * Each object (pointed to by dp) begins with a size in (dp-1)->size,
     22  * followed with "size" data Cells.  Free objects are
     23  * linked together via dp->next.
     24  */
     25 
     26 union Cell {
     27 	size_t	size;
     28 	Cell   *next;
     29 	struct {int _;} junk;	/* alignment */
     30 };
     31 
     32 struct Block {
     33 	Block  *next;		/* list of Blocks in Area */
     34 	Cell   *freelist;	/* object free list */
     35 	Cell   *last;		/* &b.cell[size] */
     36 	Cell	cell [1];	/* [size] Cells for allocation */
     37 };
     38 
     39 static Block aempty = {&aempty, aempty.cell, aempty.cell};
     40 
     41 /* create empty Area */
     42 Area *
     43 ainit(ap)
     44 	register Area *ap;
     45 {
     46 	ap->freelist = &aempty;
     47 	return ap;
     48 }
     49 
     50 /* free all object in Area */
     51 void
     52 afreeall(ap)
     53 	register Area *ap;
     54 {
     55 	register Block *bp;
     56 	register Block *tmp;
     57 
     58 	bp = ap->freelist;
     59 	if (bp != NULL && bp != &aempty) {
     60 		do {
     61 			tmp = bp->next;
     62 			free((void*)bp);
     63 			bp = tmp;
     64 		} while (bp != ap->freelist);
     65 		ap->freelist = &aempty;
     66 	}
     67 }
     68 
     69 /* allocate object from Area */
     70 void *
     71 alloc(size, ap)
     72 	size_t size;
     73 	register Area *ap;
     74 {
     75 	int cells, split;
     76 	register Block *bp;
     77 	register Cell *dp, *fp, *fpp;
     78 
     79 	if (size <= 0) {
     80 		aerror(ap, "allocate bad size");
     81 		return NULL;
     82 	}
     83 	cells = (unsigned)(size - 1) / sizeof(Cell) + 1;
     84 
     85 	/* find Cell large enough */
     86 	for (bp = ap->freelist; ; bp = bp->next) {
     87 		for (fpp = NULL, fp = bp->freelist;
     88 		     fp != bp->last; fpp = fp, fp = fpp->next)
     89 			if ((fp-1)->size >= cells)
     90 				goto Found;
     91 
     92 		/* wrapped around Block list, create new Block */
     93 		if (bp->next == ap->freelist) {
     94 			bp = (Block*) malloc(offsetof(Block, cell[ICELLS])
     95 					     + sizeof(bp->cell[0]) * cells);
     96 			if (bp == NULL) {
     97 				aerror(ap, "cannot allocate");
     98 				return NULL;
     99 			}
    100 			if (ap->freelist == &aempty)
    101 				bp->next = bp;
    102 			else {
    103 				bp->next = ap->freelist->next;
    104 				ap->freelist->next = bp;
    105 			}
    106 			bp->last = bp->cell + ICELLS + cells;
    107 			fp = bp->freelist = bp->cell + 1; /* initial free list */
    108 			(fp-1)->size = ICELLS + cells - 1;
    109 			fp->next = bp->last;
    110 			fpp = NULL;
    111 			break;
    112 		}
    113 	}
    114   Found:
    115 	ap->freelist = bp;
    116 	dp = fp;		/* allocated object */
    117 	split = (dp-1)->size - cells;
    118 	if (split < 0)
    119 		aerror(ap, "allocated object too small");
    120 	if (--split <= 0) {	/* allocate all */
    121 		fp = fp->next;
    122 	} else {		/* allocate head, free tail */
    123 		(fp-1)->size = cells;
    124 		fp += cells + 1;
    125 		(fp-1)->size = split;
    126 		fp->next = dp->next;
    127 	}
    128 	if (fpp == NULL)
    129 		bp->freelist = fp;
    130 	else
    131 		fpp->next = fp;
    132 	return (void*) dp;
    133 }
    134 
    135 /* change size of object -- like realloc */
    136 void *
    137 aresize(ptr, size, ap)
    138 	register void *ptr;
    139 	size_t size;
    140 	Area *ap;
    141 {
    142 	int cells;
    143 	register Cell *dp = (Cell*) ptr;
    144 
    145 	if (size <= 0) {
    146 		aerror(ap, "allocate bad size");
    147 		return NULL;
    148 	}
    149 	cells = (unsigned)(size - 1) / sizeof(Cell) + 1;
    150 
    151 	if (dp == NULL || (dp-1)->size < cells) { /* enlarge object */
    152 		/* XXX check for available adjacent free block */
    153 		ptr = alloc(size, ap);
    154 		if (dp != NULL) {
    155 			memcpy(ptr, dp, (dp-1)->size * sizeof(Cell));
    156 			afree((void *) dp, ap);
    157 		}
    158 	} else {		/* shrink object */
    159 		int split;
    160 
    161 		split = (dp-1)->size - cells;
    162 		if (--split <= 0) /* cannot split */
    163 			;
    164 		else {		/* shrink head, free tail */
    165 			(dp-1)->size = cells;
    166 			dp += cells + 1;
    167 			(dp-1)->size = split;
    168 			afree((void*)dp, ap);
    169 		}
    170 	}
    171 	return (void*) ptr;
    172 }
    173 
    174 void
    175 afree(ptr, ap)
    176 	void *ptr;
    177 	register Area *ap;
    178 {
    179 	register Block *bp;
    180 	register Cell *fp, *fpp;
    181 	register Cell *dp = (Cell*)ptr;
    182 
    183 	/* find Block containing Cell */
    184 	for (bp = ap->freelist; ; bp = bp->next) {
    185 		if (bp->cell <= dp && dp < bp->last)
    186 			break;
    187 		if (bp->next == ap->freelist) {
    188 			aerror(ap, "freeing with invalid area");
    189 			return;
    190 		}
    191 	}
    192 
    193 	/* find position in free list */
    194 	for (fpp = NULL, fp = bp->freelist; fp < dp; fpp = fp, fp = fpp->next)
    195 		;
    196 
    197 	if (fp == dp) {
    198 		aerror(ap, "freeing free object");
    199 		return;
    200 	}
    201 
    202 	/* join object with next */
    203 	if (dp + (dp-1)->size == fp-1) { /* adjacent */
    204 		(dp-1)->size += (fp-1)->size + 1;
    205 		dp->next = fp->next;
    206 	} else			/* non-adjacent */
    207 		dp->next = fp;
    208 
    209 	/* join previous with object */
    210 	if (fpp == NULL)
    211 		bp->freelist = dp;
    212 	else if (fpp + (fpp-1)->size == dp-1) { /* adjacent */
    213 		(fpp-1)->size += (dp-1)->size + 1;
    214 		fpp->next = dp->next;
    215 	} else			/* non-adjacent */
    216 		fpp->next = dp;
    217 }
    218 
    219 #if DEBUG_ALLOC
    220 void
    221 aprint(ap, ptr, size)
    222 	register Area *ap;
    223 	void *ptr;
    224 	size_t size;
    225 {
    226 	Block *bp;
    227 
    228 	if (!ap)
    229 		shellf("aprint: null area pointer\n");
    230 	else if (!(bp = ap->freelist))
    231 		shellf("aprint: null area freelist\n");
    232 	else if (bp == &aempty)
    233 		shellf("aprint: area is empty\n");
    234 	else {
    235 		int i;
    236 		Cell *fp;
    237 
    238 		for (i = 0; !i || bp != ap->freelist; bp = bp->next, i++) {
    239 			if (ptr) {
    240 				void *eptr = (void *) (((char *) ptr) + size);
    241 				/* print block only if it overlaps ptr/size */
    242 				if (!((ptr >= (void *) bp
    243 				       && ptr <= (void *) bp->last)
    244 				      || (eptr >= (void *) bp
    245 				         && eptr <= (void *) bp->last)))
    246 					continue;
    247 				shellf("aprint: overlap of 0x%p .. 0x%p\n",
    248 					ptr, eptr);
    249 			}
    250 			shellf("aprint: block %2d: 0x%p .. 0x%p (%d)\n", i,
    251 				bp->cell, bp->last,
    252 				(char *) bp->last - (char *) bp->cell);
    253 			for (fp = bp->freelist; fp != bp->last; fp = fp->next)
    254 				shellf(
    255 				    "aprint:   0x%p .. 0x%p (%d) free\n",
    256 					(fp-1), (fp-1) + (fp-1)->size,
    257 					(fp-1)->size * sizeof(Cell));
    258 		}
    259 	}
    260 }
    261 #endif /* DEBUG_ALLOC */
    262 
    263 
    264 #ifdef TEST_ALLOC
    265 
    266 Area a;
    267 
    268 main(int argc, char **argv) {
    269 	int i;
    270 	char *p [9];
    271 
    272 	ainit(&a);
    273 	for (i = 0; i < 9; i++) {
    274 		p[i] = alloc(124, &a);
    275 		printf("alloc: %x\n", p[i]);
    276 	}
    277 	for (i = 1; i < argc; i++)
    278 		afree(p[atoi(argv[i])], &a);
    279 	afreeall(&a);
    280 	return 0;
    281 }
    282 
    283 void aerror(Area *ap, const char *msg) {
    284 	abort();
    285 }
    286 
    287 #endif
    288 
    289