home *** CD-ROM | disk | FTP | other *** search
- /* from the TOS GCC library */
- /* malloc, free, realloc: dynamic memory allocation */
-
- #include <stddef.h> /* for size_t */
- #include <memory.h>
- #include <string.h>
- #include <assert.h>
-
- extern long _stksize;
- extern void *_sbrk();
-
- /* minimum chunk to ask OS for */
- static size_t MINHUNK = 4096L; /* default */
- static size_t MAXHUNK = 32*1024L; /* max. default */
-
- /* CAUTION: use _mallocChunkSize() to tailor to your environment,
- do not make the default too large, as the compiler
- gets screwed on a 1M machine otherwise (stack/heap clash)
- */
-
- struct mem_chunk
- {
- long valid;
- #define VAL_FREE 0xf4ee0abc
- #define VAL_ALLOC 0xa11c0abc
-
- struct mem_chunk *next;
- long size;
- };
-
- /* linked list of free blocks */
-
- static struct mem_chunk _mchunk_free_list = { VAL_FREE, NULL, 0L };
-
- /* flag to control zero'ing of malloc'ed chunks */
- static int _ZeroMallocs = 0;
-
-
- #if 0
- asm(".text; .even; .globl _mlalloc; _mlalloc:"); /* dept of dirty tricks */
- #endif
-
- void * malloc(n)
- size_t n;
- {
- struct mem_chunk *p, *q;
- long sz;
- extern void *_heapbase;
-
- /* add a mem_chunk to required size and round up */
- n = n + sizeof(struct mem_chunk);
- n = (7 + n) & ~7;
- /* look for first block big enough in free list */
- p = &_mchunk_free_list;
- q = _mchunk_free_list.next;
-
- while ((q != NULL) && (q->size < n))
- {
- p = q;
- q = q->next;
- }
-
- /* if not enough memory, get more from the system */
- if (q == NULL)
- {
- if ((_heapbase != NULL) || (n > MINHUNK))
- sz = n;
- else {
- sz = MINHUNK;
- if (MINHUNK < MAXHUNK)
- MINHUNK *= 2;
- }
- q = (struct mem_chunk * )_sbrk(sz);
-
- if (((long)q) == -1) /* can't alloc any more? */
- return(NULL);
-
- p->next = q;
- q->size = sz;
- q->next = NULL;
- q->valid = VAL_FREE;
- }
-
- if (q->size > n + sizeof(struct mem_chunk))
- { /* split, leave part of free list */
- q->size -= n;
- q = (struct mem_chunk * )(((long) q) + q->size);
- q->size = n;
- q->valid = VAL_ALLOC;
- }
- else
- { /* just unlink it */
- p->next = q->next;
- q->valid = VAL_ALLOC;
- }
-
- q->next = NULL;
- q++; /* hand back ptr to after chunk desc */
- if(_ZeroMallocs != 0)
- bzero((void *)q, (size_t)(n - sizeof(struct mem_chunk)));
-
- return((void * )q);
- }
-
- void free(param)
- void *param;
- {
- struct mem_chunk *o, *p, *q, *s;
- struct mem_chunk *r = (struct mem_chunk *) param;
- extern void *_heapbase;
-
- /* free(NULL) should do nothing */
- if (r == 0)
- return;
-
- /* move back to uncover the mem_chunk */
- r--; /* there it is! */
-
- if (r->valid != VAL_ALLOC)
- return;
-
- r->valid = VAL_FREE;
-
- /* stick it into free list, preserving ascending address order */
- o = NULL;
- p = &_mchunk_free_list;
- q = _mchunk_free_list.next;
- while (q != NULL && q < r)
- {
- o = p;
- p = q;
- q = q->next;
- }
-
- /* merge after if possible */
- s = (struct mem_chunk * )(((long) r) + r->size);
- if (q != NULL && s >= q)
- {
- assert(s == q);
- r->size += q->size;
- q = q->next;
- s->size = 0;
- s->next = NULL;
- }
- r->next = q;
-
- /* merge before if possible, otherwise link it in */
- s = (struct mem_chunk * )(((long) p) + p->size);
- if (s >= r && p != &_mchunk_free_list)
- /* remember: r may be below &_mchunk_free_list in memory */
- {
- assert(s == r);
- p->size += r->size;
- p->next = r->next;
- r->size = 0;
- r->next = NULL;
- s = (struct mem_chunk * )(((long) p) + p->size);
- if (_heapbase != NULL && s >= (struct mem_chunk *) _heapbase) {
- assert(s == _heapbase);
- _heapbase = (char *) p;
- _stksize += p->size;
- o->next = NULL; /* o is always != NULL here */
- }
- }
- else
- {
- s = (struct mem_chunk * )(((long) r) + r->size);
- if (_heapbase != NULL && s >= (struct mem_chunk *) _heapbase) {
- assert(s == _heapbase);
- _heapbase = (char *) r;
- _stksize += r->size;
- p->next = NULL;
- } else p->next = r;
- }
- }
-
- #if 0
- asm(".text; .even; .globl _relalloc,_realloc; _relalloc: jra _realloc");
- #ifdef NDEBUG
- static char *__dummy = ""; /* otherwise we get a bra with 0 offset above */
- #endif
- #endif
-
- void * realloc(_r, n)
- void *_r;
- size_t n;
- {
- struct mem_chunk *p, *q, *r = _r;
- long sz;
-
- /* obscure features: realloc(NULL,n) is the same as malloc(n)
- * realloc(p, 0) is the same as free(p)
- */
- if (!r)
- return malloc(n);
- if (n == 0) {
- free(_r);
- return NULL;
- }
- p = r - 1;
- sz = (n + sizeof(struct mem_chunk) + 7) & ~7;
-
- if (p->size > sz)
- { /* block too big, split in two */
- q = (struct mem_chunk * )(((long) p) + sz);
- q->size = p->size - sz;
- q->valid = VAL_ALLOC;
- free(q + 1);
- p->size = sz;
- }
- else
- if (p->size < sz)
- { /* block too small, get new one */
- struct mem_chunk *s, *t;
- q = &_mchunk_free_list;
- t = _mchunk_free_list.next;
- while (t != NULL && t < p)
- {
- q = t;
- t = t->next;
- }
-
- /* merge after if possible */
- s = (struct mem_chunk * )(((long) p) + p->size);
- if (t != NULL && s >= t && p->size + t->size >= sz)
- {
- assert(s == t);
- p->size += t->size;
- q->next = t->next;
- t->size = 0;
- t->next = NULL;
- }
- else
- {
- q = (struct mem_chunk * )malloc(n);
- if (q != NULL)
- {
- n = p->size - sizeof(struct mem_chunk);
- bcopy(r, q, n);
- free(r); /* free r only if we got a new block */
- }
- r = q;
- }
- }
- /* else current block will do just fine */
- return((void * )r);
- }
-
- #if 0
- asm(".text; .even; .globl _clalloc; _clalloc:");
- #endif
-
- void * calloc(n, sz)
- size_t n, sz;
- {
- char *r;
- size_t total;
-
- total = n * sz;
- if ((r = malloc(total)) != NULL) {
- bzero(r, total);
- }
- return(r);
- }
-
- /*
- * Set zero block after malloc flag
- */
- void _malloczero(yes)
- int yes;
- {
- _ZeroMallocs = yes;
- }
-
- /*
- * tune chunk size
- */
- void _mallocChunkSize (siz)
- size_t siz;
- {
- MAXHUNK = MINHUNK = siz;
- }
-