mmalloc from last version to be included in gdb.
[ocaml-ancient.git] / mmalloc / mfree.c
diff --git a/mmalloc/mfree.c b/mmalloc/mfree.c
new file mode 100644 (file)
index 0000000..c509ac6
--- /dev/null
@@ -0,0 +1,247 @@
+/* Free a block of memory allocated by `mmalloc'.
+   Copyright 1990, 1991, 1992 Free Software Foundation
+
+   Written May 1989 by Mike Haertel.
+   Heavily modified Mar 1992 by Fred Fish.  (fnf@cygnus.com)
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+   The author may be reached (Email) at the address mike@ai.mit.edu,
+   or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include "mmprivate.h"
+
+/* Return memory to the heap.
+   Like `mfree' but don't call a mfree_hook if there is one.  */
+
+void
+__mmalloc_free (mdp, ptr)
+  struct mdesc *mdp;
+  PTR ptr;
+{
+  int type;
+  size_t block, blocks;
+  register size_t i;
+  struct list *prev, *next;
+
+  block = BLOCK (ptr);
+
+  type = mdp -> heapinfo[block].busy.type;
+  switch (type)
+    {
+    case 0:
+      /* Get as many statistics as early as we can.  */
+      mdp -> heapstats.chunks_used--;
+      mdp -> heapstats.bytes_used -=
+         mdp -> heapinfo[block].busy.info.size * BLOCKSIZE;
+      mdp -> heapstats.bytes_free +=
+         mdp -> heapinfo[block].busy.info.size * BLOCKSIZE;
+
+      /* Find the free cluster previous to this one in the free list.
+        Start searching at the last block referenced; this may benefit
+        programs with locality of allocation.  */
+      i = mdp -> heapindex;
+      if (i > block)
+       {
+         while (i > block)
+           {
+             i = mdp -> heapinfo[i].free.prev;
+           }
+       }
+      else
+       {
+         do
+           {
+             i = mdp -> heapinfo[i].free.next;
+           }
+         while ((i != 0) && (i < block));
+         i = mdp -> heapinfo[i].free.prev;
+       }
+
+      /* Determine how to link this block into the free list.  */
+      if (block == i + mdp -> heapinfo[i].free.size)
+       {
+         /* Coalesce this block with its predecessor.  */
+         mdp -> heapinfo[i].free.size +=
+           mdp -> heapinfo[block].busy.info.size;
+         block = i;
+       }
+      else
+       {
+         /* Really link this block back into the free list.  */
+         mdp -> heapinfo[block].free.size =
+           mdp -> heapinfo[block].busy.info.size;
+         mdp -> heapinfo[block].free.next = mdp -> heapinfo[i].free.next;
+         mdp -> heapinfo[block].free.prev = i;
+         mdp -> heapinfo[i].free.next = block;
+         mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev = block;
+         mdp -> heapstats.chunks_free++;
+       }
+
+      /* Now that the block is linked in, see if we can coalesce it
+        with its successor (by deleting its successor from the list
+        and adding in its size).  */
+      if (block + mdp -> heapinfo[block].free.size ==
+         mdp -> heapinfo[block].free.next)
+       {
+         mdp -> heapinfo[block].free.size
+           += mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.size;
+         mdp -> heapinfo[block].free.next
+           = mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.next;
+         mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev = block;
+         mdp -> heapstats.chunks_free--;
+       }
+
+      /* Now see if we can return stuff to the system.  */
+      blocks = mdp -> heapinfo[block].free.size;
+      if (blocks >= FINAL_FREE_BLOCKS && block + blocks == mdp -> heaplimit
+         && mdp -> morecore (mdp, 0) == ADDRESS (block + blocks))
+       {
+         register size_t bytes = blocks * BLOCKSIZE;
+         mdp -> heaplimit -= blocks;
+         mdp -> morecore (mdp, -bytes);
+         mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
+           = mdp -> heapinfo[block].free.next;
+         mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
+           = mdp -> heapinfo[block].free.prev;
+         block = mdp -> heapinfo[block].free.prev;
+         mdp -> heapstats.chunks_free--;
+         mdp -> heapstats.bytes_free -= bytes;
+       }
+
+      /* Set the next search to begin at this block.  */
+      mdp -> heapindex = block;
+      break;
+
+    default:
+      /* Do some of the statistics.  */
+      mdp -> heapstats.chunks_used--;
+      mdp -> heapstats.bytes_used -= 1 << type;
+      mdp -> heapstats.chunks_free++;
+      mdp -> heapstats.bytes_free += 1 << type;
+
+      /* Get the address of the first free fragment in this block.  */
+      prev = (struct list *)
+       ((char *) ADDRESS(block) +
+        (mdp -> heapinfo[block].busy.info.frag.first << type));
+
+      if (mdp -> heapinfo[block].busy.info.frag.nfree ==
+         (BLOCKSIZE >> type) - 1)
+       {
+         /* If all fragments of this block are free, remove them
+            from the fragment list and free the whole block.  */
+         next = prev;
+         for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
+           {
+             next = next -> next;
+           }
+         prev -> prev -> next = next;
+         if (next != NULL)
+           {
+             next -> prev = prev -> prev;
+           }
+         mdp -> heapinfo[block].busy.type = 0;
+         mdp -> heapinfo[block].busy.info.size = 1;
+
+         /* Keep the statistics accurate.  */
+         mdp -> heapstats.chunks_used++;
+         mdp -> heapstats.bytes_used += BLOCKSIZE;
+         mdp -> heapstats.chunks_free -= BLOCKSIZE >> type;
+         mdp -> heapstats.bytes_free -= BLOCKSIZE;
+
+         mfree ((PTR) mdp, (PTR) ADDRESS(block));
+       }
+      else if (mdp -> heapinfo[block].busy.info.frag.nfree != 0)
+       {
+         /* If some fragments of this block are free, link this
+            fragment into the fragment list after the first free
+            fragment of this block. */
+         next = (struct list *) ptr;
+         next -> next = prev -> next;
+         next -> prev = prev;
+         prev -> next = next;
+         if (next -> next != NULL)
+           {
+             next -> next -> prev = next;
+           }
+         ++mdp -> heapinfo[block].busy.info.frag.nfree;
+       }
+      else
+       {
+         /* No fragments of this block are free, so link this
+            fragment into the fragment list and announce that
+            it is the first free fragment of this block. */
+         prev = (struct list *) ptr;
+         mdp -> heapinfo[block].busy.info.frag.nfree = 1;
+         mdp -> heapinfo[block].busy.info.frag.first =
+           RESIDUAL (ptr, BLOCKSIZE) >> type;
+         prev -> next = mdp -> fraghead[type].next;
+         prev -> prev = &mdp -> fraghead[type];
+         prev -> prev -> next = prev;
+         if (prev -> next != NULL)
+           {
+             prev -> next -> prev = prev;
+           }
+       }
+      break;
+    }
+}
+
+/* Return memory to the heap.  */
+
+void
+mfree (md, ptr)
+  PTR md;
+  PTR ptr;
+{
+  struct mdesc *mdp;
+  register struct alignlist *l;
+
+  if (ptr != NULL)
+    {
+      mdp = MD_TO_MDP (md);
+      for (l = mdp -> aligned_blocks; l != NULL; l = l -> next)
+       {
+         if (l -> aligned == ptr)
+           {
+             l -> aligned = NULL;  /* Mark the slot in the list as free. */
+             ptr = l -> exact;
+             break;
+           }
+       }      
+      if (mdp -> mfree_hook != NULL)
+       {
+         (*mdp -> mfree_hook) (md, ptr);
+       }
+      else
+       {
+         __mmalloc_free (mdp, ptr);
+       }
+    }
+}
+
+/* When using this package, provide a version of malloc/realloc/free built
+   on top of it, so that if we use the default sbrk() region we will not
+   collide with another malloc package trying to do the same thing, if
+   the application contains any "hidden" calls to malloc/realloc/free (such
+   as inside a system library). */
+
+void
+free (ptr)
+  PTR ptr;
+{
+  mfree ((PTR) NULL, ptr);
+}