/* * mm.c: simple memory management for teeny-shell * * it's a dumb heap- when we are interrupted out of parse, we can rewind * by the simple expedient of flushing the heap. Multiple marks can be * supported. A future enhancement might be to use mmalloc to establish * a chain of heap segments. * * 90% of the scanner/parser is satisfied by this routine. The parts that * can't be satisfied are the bits where mrealloc is used, and from the * _scanner_, I should be able to keep mreallocating top of heap. * * so, while scanning, I can do: * p = mm_new(50); * p = mm_expand(p, *p+50); * and, inside ^* code, I do a * x = mm_mark(); * p = mm_new(50); * p = mm_expand(p, *p+50); * mm_release(x); ... and the item is back at tos, ready for expansion. * * after I've completely parsed a subtree, I copy it into permanent memory * via a large mmalloc (this is where I'd win by doing mmallocs whenever I * do a _mark_....) and reset the heap. */ #include #define MMSIZE 5120 static int heap[MMSIZE]; static int *top = heap; /* * newheap() cleans everything off the heap unconditionally */ newheap() { top = heap; } /* newheap */ /* * mm_mark() returns a region mark that we can allocate above */ MARKP mm_mark() { return (void*)top; } /* mark */ /* * mm_release() cuts the heap back to mark */ mm_release(mp) MARKP mp; { if (mp >= heap && mp < heap+MMSIZE && (1 & (long)mp) == 0) top = mp; } /* mm_release */ /* * mm_new() returns a block of memory off the heap, or 0 if the request can't * be satisfied */ void * mm_new(size) { register int *blk; size = (size+sizeof(int)-1)/sizeof(int); if (top+size+1 < heap+sizeof heap) { blk = top; blk[0] = size; top += (1+size); return (void*)(1+blk); } return (void *)0; } /* mm_new */ /* * mm_expand() expands a block of memory on the heap, provided it is the topmost * item there. */ void * mm_expand(item, newsize) int *item; { if (item == (int*)0) return new(newsize); else if (item + item[-1] == top) { release(item-1); /* make item top-of-heap again */ return new(newsize); /* then mreallocate on it */ } return (void*)0; } /* mm_expand */ #ifdef TEST main() { char *p, *q, *m1, *m2; register i; mm_newheap(); m1 = mm_mark(); p = mm_new(1); for (i=1;i<10; i++) { p = mm_expand(p, i*10); if (p == (char*)0) { fprintf(stderr, "expand failed on p (size %d)!\n", i*10); exit(0); } } m2 = mm_mark(); q = mm_new(40); mm_release(m2); for (i=11; i<20; i++) { p = mm_expand(p, i*10); if (p == (char*)0) { fprintf(stderr, "expand failed on p (size %d)!\n", i*10); exit(0); } } } #endif