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