/* from the TOS GCC library */ /* malloc, free, realloc: dynamic memory allocation */ /* ERS: added mlalloc, relalloc, etc. for 16 bit compilers. Changed argument of malloc, etc., to size_t (per ANSI draft). */ /* 5/2/92 sb -- modified for Heat-n-Serve C to accomodate its 16-bit size_t */ /* 5/5/92 sb -- split off realloc() & calloc() to reduce library drag */ #include #include /* for size_t */ #include #include #include #include #include #include "lib.h" extern long _stksize; void *_malloc __PROTO((unsigned long)); /* 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) */ /* linked list of free blocks struct defined in lib.h */ struct mem_chunk _mchunk_free_list = { VAL_FREE, NULL, 0L }; /* flag to control zero'ing of malloc'ed chunks */ static int _ZeroMallocs = 0; __EXTERN void _bzero __PROTO((void *, unsigned long)); #ifdef __GNUC__ asm(".stabs \"_malloc\",5,0,0,__malloc"); /* dept of clean tricks */ #endif void * _malloc(n) unsigned long n; { struct mem_chunk *p, *q; long sz; extern void *_heapbase; extern short _split_mem; /* 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 (((!_split_mem) && (_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); /* Note: q may be below the highest allocated chunk */ p = &_mchunk_free_list; while (p->next != NULL && q > p->next) p = p->next; q->size = sz; q->next = p->next; q->valid = VAL_FREE; p->next = q; } 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, (long)(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; extern short _split_mem; /* 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 ((!_split_mem) && _heapbase != NULL && s >= (struct mem_chunk *) _heapbase && s < (struct mem_chunk *) ((char *)_heapbase + _stksize)) { assert(s == (struct mem_chunk *) _heapbase); _heapbase = (void *) p; _stksize += p->size; o->next = p->next; /* o is always != NULL here */ } } else { s = (struct mem_chunk * )(((long) r) + r->size); if ((!_split_mem) && _heapbase != NULL && s >= (struct mem_chunk *) _heapbase && s < (struct mem_chunk *) ((char *)_heapbase + _stksize)) { assert(s == (struct mem_chunk *) _heapbase); _heapbase = (void *) r; _stksize += r->size; p->next = r->next; } else p->next = 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; } #ifndef __GNUC__ void * malloc(n) size_t n; { return _malloc((unsigned long) n); } #endif