home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / editors / mntemacs.zoo / src / lib+ / malloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-30  |  8.0 KB  |  361 lines

  1. /* from the TOS GCC library */
  2. /* malloc, free, realloc: dynamic memory allocation */
  3. /* ERS: added mlalloc, relalloc, etc. for 16 bit compilers. Changed
  4.    argument of malloc, etc.,  to size_t (per ANSI draft). */
  5. /* jrb: added support for allocation from _heapbase when _stksize == -1 
  6.     thanks to Piet van Oostrum & Atze Dijkstra for this idea and
  7.         their diffs. */
  8. /* Added malloc_init and warnfunction for emacs support
  9.  * This will only work if you set _stksize = -1. Otherwise we have no
  10.  * correct lim_data and data_bytes_unused
  11.  * [[ i have a solution for this, but i included this stuff for emacs only ]]
  12.  * shrink heap if free'd block is at the top of the heap
  13.  * added sbrk (works either with heap or Malloc) (er)
  14.  */
  15.  
  16. #include <stddef.h>    /* for size_t */
  17. #include <memory.h>
  18. #ifndef __MINT__
  19. #include <unixlib.h>
  20. #else
  21. #include <unistd.h>
  22. #endif
  23. #include <string.h>
  24. #include <osbind.h>
  25. #include <assert.h>
  26.  
  27. extern void *_heapbase;
  28. extern long _stksize;
  29.  
  30. /* minimum chunk to ask OS for */
  31. static size_t MINHUNK =    4096L;    /* default */
  32. static size_t MAXHUNK = 16*1024L; /* max. default */
  33.  
  34.     /* CAUTION: use _mallocChunkSize() to tailor to your environment,
  35.             do not make the default too large, as the compiler
  36.             gets screwed on a 1M machine otherwise (stack/heap clash)
  37.      */
  38.  
  39. struct mem_chunk 
  40.     {
  41.     struct mem_chunk *next;
  42.     long size;
  43.     };
  44.  
  45. /* linked list of free blocks */
  46.  
  47. static struct mem_chunk _mchunk_free_list = { NULL, 0L };
  48.  
  49. /* flag to control zero'ing of malloc'ed chunks */
  50. static int _ZeroMallocs = 0;
  51.  
  52. /* Number of bytes of writable memory we can expect to be able to get */
  53. extern long    __lim_data;            /* in sbrk.c */
  54. extern long    __malloc_bytes_in_free_list;    /* in sbrk.c */
  55. extern long    malloc_sbrk_used;        /* in sbrk.c */
  56. extern long    malloc_sbrk_unused;        /* in sbrk.c */
  57.  
  58. /* Level number of warnings already issued.
  59.   0 -- no warnings issued.
  60.   1 -- 75% warning already issued.
  61.   2 -- 85% warning already issued.
  62. */
  63. static int warnlevel;
  64.  
  65. /* Function to call to issue a warning;
  66.    0 means don't issue them.  */
  67. static void (*warnfunction) ();
  68.  
  69. /* Cause reinitialization based on job parameters;
  70.   also declare where the end of pure storage is. */
  71. void
  72. malloc_init (start, warnfun)
  73.      void *start;
  74.      void (*warnfun) ();
  75. {
  76.   __lim_data = 0;
  77.   __lim_data += (long) sbrk(0) - (long) start;
  78.   warnlevel = 0;
  79.   if (warnfun != (void (*)) -1)
  80.     warnfunction = warnfun;
  81. }
  82.  
  83. static void
  84. do_warning(void)
  85. {
  86.     if(warnfunction)
  87.     switch (warnlevel) {
  88.         case 0: 
  89.         if (malloc_sbrk_used > (__lim_data / 4) * 3) {
  90.             warnlevel++;
  91.             (*warnfunction) ("Warning: past 75% of memory limit\n");
  92.         }
  93.         break;
  94.         case 1: 
  95.         if (malloc_sbrk_used > (__lim_data / 20) * 17) {
  96.             warnlevel++;
  97.             (*warnfunction) ("Warning: past 85% of memory limit\n");
  98.         }
  99.         break;
  100.         case 2: 
  101.         if (malloc_sbrk_used > (__lim_data / 20) * 19) {
  102.             warnlevel++;
  103.         (*warnfunction) ("Warning: past 95% of memory limit\n");
  104.         }
  105.         break;
  106.     }
  107. }
  108.  
  109. asm(".text; .even; .globl _mlalloc; _mlalloc:");
  110.  
  111. void * malloc(n)
  112. size_t n; 
  113. {
  114.   struct mem_chunk *p, *q;
  115.   long sz;
  116.  
  117. /* add a mem_chunk to required size and round up */
  118.   n = n + sizeof(struct mem_chunk);
  119.   n = (7 + n) & ~7;
  120. /* look for first block big enough in free list */
  121.   p = &_mchunk_free_list;
  122.   q = _mchunk_free_list.next;
  123.  
  124.   while ((q != NULL) && (q->size < n))
  125.     {
  126.     p = q;
  127.     q = q->next;
  128.     }
  129.  
  130. /* if not enough memory, get more from the system */
  131.   if (q == NULL) 
  132.     {
  133.     if ((_heapbase != NULL) || (n > MINHUNK))
  134.         sz = n;
  135.     else {
  136.         sz = MINHUNK;
  137.         if (MINHUNK < MAXHUNK)
  138.             MINHUNK *= 2;
  139.     }
  140.     q = (struct mem_chunk * )lsbrk(sz);
  141.  
  142.     if (((long)q) <= 0)         /* can't alloc any more? */
  143.         return(NULL);
  144.  
  145.     p->next = q;
  146.     q->size = sz;
  147.     q->next = NULL;
  148.     }
  149.         
  150.   if (q->size > n + sizeof(struct mem_chunk))
  151.     {                /* split, leave part of free list */
  152.     q->size -= n;
  153.     q = (struct mem_chunk * )(((long) q) + q->size);
  154.     q->size = n;
  155.     }
  156.     else
  157.     {                /* just unlink it */
  158.     p->next = q->next;
  159.     }
  160.     
  161.   malloc_sbrk_used += q->size;
  162.   malloc_sbrk_unused -= q->size;
  163.   __malloc_bytes_in_free_list -= q->size;
  164.   do_warning();
  165.   q->next = NULL;
  166.   q++;        /* hand back ptr to after chunk desc */
  167.   if(_ZeroMallocs != 0)
  168. #ifndef __MINT__  
  169.       lbzero((void *)q, (long)(n - sizeof(struct mem_chunk)));
  170. #else 
  171.       bzero((void *)q, (long)(n - sizeof(struct mem_chunk)));
  172. #endif
  173.   return((void * )q);
  174. }
  175.  
  176. void free(param)
  177.     void *param;
  178. {
  179.   struct mem_chunk *o, *p, *q, *s;
  180.   struct mem_chunk *r = (struct mem_chunk *) param;
  181.  
  182. /* free(NULL) should do nothing */
  183.   if (r == 0)
  184.      return;
  185.  
  186. /* move back to uncover the mem_chunk */
  187.   r--;            /* there it is! */
  188.  
  189.   assert(!(r->size & 7));
  190.   malloc_sbrk_used -= r->size;
  191.   malloc_sbrk_unused += r->size;
  192.   __malloc_bytes_in_free_list += r->size;
  193.   /* lbzero(r + 1,r->size - sizeof(struct mem_chunk)); */
  194.  
  195. /* stick it into free list, preserving ascending address order */
  196.   o = NULL;
  197.   p = &_mchunk_free_list;
  198.   q = _mchunk_free_list.next;
  199.   while (q != NULL && q < r) 
  200.     {
  201.     o = p;
  202.     p = q;
  203.     q = q->next;
  204.     }
  205.  
  206. /* merge after if possible */
  207.   s = (struct mem_chunk * )(((long) r) + r->size);
  208.   if (q != NULL && s >= q) 
  209.     {
  210.     assert(s == q);
  211.     r->size += q->size;
  212.     q = q->next;
  213.     s->size = 0;
  214.     s->next = NULL;
  215.     }
  216.   r->next = q;
  217.     
  218. /* merge before if possible, otherwise link it in */
  219.   s = (struct mem_chunk * )(((long) p) + p->size);
  220.   if (s >= r && p != &_mchunk_free_list)
  221.     /* remember: r may be below &_mchunk_free_list in memory */
  222.     {
  223.     assert(s == r);
  224.     p->size += r->size;
  225.     p->next = r->next;
  226.     r->size = 0;
  227.     r->next = NULL;
  228.     s = (struct mem_chunk * )(((long) p) + p->size);
  229.     if (_heapbase != NULL && s >= (struct mem_chunk *) _heapbase) {
  230.       assert(s == _heapbase);
  231.       lsbrk(-p->size);
  232.       o->next = NULL;    /* o is always != NULL here */
  233.     }
  234.     }
  235.     else
  236.         {
  237.       s = (struct mem_chunk * )(((long) r) + r->size);
  238.       if (_heapbase != NULL && s >= (struct mem_chunk *) _heapbase) {
  239.         assert(s == _heapbase);
  240.         lsbrk(-r->size);
  241.         p->next = NULL;
  242.       } else p->next = r;
  243.     }
  244. }
  245.  
  246. asm(".text; .even; .globl _relalloc,_realloc; _relalloc: jra _realloc");
  247. #ifdef NDEBUG
  248. static char *__dummy = ""; /* otherwise we get a bra with 0 offset above */
  249. #endif
  250.  
  251. void * realloc(_r, n)
  252. void *_r;
  253. size_t n;
  254. {
  255.   struct mem_chunk *p, *q, *r = _r;
  256.   long *src, *dst;
  257.   long sz;
  258.  
  259. /* obscure features: realloc(NULL,n) is the same as malloc(n)
  260.  *               realloc(p, 0) is the same as free(p)
  261.  */
  262.   if (!r)
  263.     return malloc(n);
  264.   if (n == 0) {
  265.     free(_r);
  266.     return NULL;
  267.   }
  268.   p = r - 1;
  269.   sz = (n + sizeof(struct mem_chunk) + 7) & ~7;
  270.  
  271.   if (p->size > sz) 
  272.     {            /* block too big, split in two */
  273.     q = (struct mem_chunk * )(((long) p) + sz);
  274.     q->size = p->size - sz;
  275.     free(q + 1);
  276.     p->size = sz;
  277.     }
  278.     else 
  279.   if (p->size < sz)
  280.     {            /* block too small, get new one */
  281.     struct mem_chunk *s, *t;
  282.     q = &_mchunk_free_list;
  283.     t = _mchunk_free_list.next;
  284.     while (t != NULL && t < p)
  285.       {
  286.       q = t;
  287.       t = t->next;
  288.       }
  289.  
  290.     /* merge after if possible */
  291.     s = (struct mem_chunk * )(((long) p) + p->size);
  292.     if (t != NULL && s >= t && p->size + t->size >= sz)
  293.       {
  294.       assert(s == t);
  295.       p->size += t->size;
  296.       q->next = t->next;
  297.       malloc_sbrk_used += t->size;
  298.       malloc_sbrk_unused -= t->size;
  299.       __malloc_bytes_in_free_list -= t->size;
  300.       do_warning();
  301.       t->size = 0;
  302.       t->next = NULL;
  303.       }
  304.     else
  305.       {
  306.       dst = (long *) q = (struct mem_chunk * )malloc(n);
  307.       if (q != NULL)
  308.     {
  309.     src = (long * )r;
  310.     n = (p->size - sizeof(struct mem_chunk)) >> 2;
  311.     while (n--) 
  312.       {
  313.       *dst++ = *src++;
  314.       }
  315.         free(r);    /* free r only if we got a new block */
  316.         }
  317.       /* else we could try to mlalloc the rest and hope that we can merge */
  318.       r = q;
  319.     }
  320.   }
  321.   /* else current block will do just fine */
  322.   return((void * )r);
  323. }
  324.  
  325. asm(".text; .even; .globl _clalloc; _clalloc:");
  326. void * calloc(n, sz)
  327. size_t n, sz;
  328. {
  329.   char *r;
  330.   size_t total;
  331.  
  332.   total = n * sz;
  333.   if ((r = malloc(total)) != NULL)
  334.     {
  335. #ifndef __MINT__
  336.     lbzero(r, total);
  337. #else
  338.     bzero(r, total);
  339. #endif
  340.     }
  341.   return(r);
  342. }
  343.  
  344. /*
  345.  * Set zero block after malloc flag
  346.  */
  347. void _malloczero(yes)
  348. int yes;
  349. {
  350.     _ZeroMallocs = yes;
  351. }
  352.  
  353. /*
  354.  * tune chunk size
  355.  */
  356. void _mallocChunkSize (siz)
  357. size_t siz;
  358. {
  359.     MAXHUNK = MINHUNK = siz;
  360. }
  361.