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