Home | History | Annotate | Line # | Download | only in dist
      1  1.1  christos /*	$NetBSD: free.c,v 1.1.1.1 2016/01/13 21:42:18 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* Free a block of memory allocated by `malloc'.
      4  1.1  christos    Copyright 1990, 1991, 1992, 1994 Free Software Foundation, Inc.
      5  1.1  christos 		  Written May 1989 by Mike Haertel.
      6  1.1  christos 
      7  1.1  christos This library is free software; you can redistribute it and/or
      8  1.1  christos modify it under the terms of the GNU Library General Public License as
      9  1.1  christos published by the Free Software Foundation; either version 2 of the
     10  1.1  christos License, or (at your option) any later version.
     11  1.1  christos 
     12  1.1  christos This library is distributed in the hope that it will be useful,
     13  1.1  christos but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  1.1  christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  1.1  christos Library General Public License for more details.
     16  1.1  christos 
     17  1.1  christos You should have received a copy of the GNU Library General Public
     18  1.1  christos License along with this library; see the file COPYING.LIB.  If
     19  1.1  christos not, write to the Free Software Foundation, Inc., 675 Mass Ave,
     20  1.1  christos Cambridge, MA 02139, USA.
     21  1.1  christos 
     22  1.1  christos    The author may be reached (Email) at the address mike (at) ai.mit.edu,
     23  1.1  christos    or (US mail) as Mike Haertel c/o Free Software Foundation.  */
     24  1.1  christos 
     25  1.1  christos #ifndef	_MALLOC_INTERNAL
     26  1.1  christos #define _MALLOC_INTERNAL
     27  1.1  christos #include <malloc.h>
     28  1.1  christos #endif
     29  1.1  christos 
     30  1.1  christos /* Debugging hook for free.  */
     31  1.1  christos void (*__free_hook) __P ((__ptr_t __ptr));
     32  1.1  christos 
     33  1.1  christos /* List of blocks allocated by memalign.  */
     34  1.1  christos struct alignlist *_aligned_blocks = NULL;
     35  1.1  christos 
     36  1.1  christos /* Return memory to the heap.
     37  1.1  christos    Like `free' but don't call a __free_hook if there is one.  */
     38  1.1  christos void
     39  1.1  christos _free_internal (ptr)
     40  1.1  christos      __ptr_t ptr;
     41  1.1  christos {
     42  1.1  christos   int type;
     43  1.1  christos   __malloc_size_t block, blocks;
     44  1.1  christos   register __malloc_size_t i;
     45  1.1  christos   struct list *prev, *next;
     46  1.1  christos 
     47  1.1  christos   block = BLOCK (ptr);
     48  1.1  christos 
     49  1.1  christos   type = _heapinfo[block].busy.type;
     50  1.1  christos   switch (type)
     51  1.1  christos     {
     52  1.1  christos     case 0:
     53  1.1  christos       /* Get as many statistics as early as we can.  */
     54  1.1  christos       --_chunks_used;
     55  1.1  christos       _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE;
     56  1.1  christos       _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE;
     57  1.1  christos 
     58  1.1  christos       /* Find the free cluster previous to this one in the free list.
     59  1.1  christos 	 Start searching at the last block referenced; this may benefit
     60  1.1  christos 	 programs with locality of allocation.  */
     61  1.1  christos       i = _heapindex;
     62  1.1  christos       if (i > block)
     63  1.1  christos 	while (i > block)
     64  1.1  christos 	  i = _heapinfo[i].free.prev;
     65  1.1  christos       else
     66  1.1  christos 	{
     67  1.1  christos 	  do
     68  1.1  christos 	    i = _heapinfo[i].free.next;
     69  1.1  christos 	  while (i > 0 && i < block);
     70  1.1  christos 	  i = _heapinfo[i].free.prev;
     71  1.1  christos 	}
     72  1.1  christos 
     73  1.1  christos       /* Determine how to link this block into the free list.  */
     74  1.1  christos       if (block == i + _heapinfo[i].free.size)
     75  1.1  christos 	{
     76  1.1  christos 	  /* Coalesce this block with its predecessor.  */
     77  1.1  christos 	  _heapinfo[i].free.size += _heapinfo[block].busy.info.size;
     78  1.1  christos 	  block = i;
     79  1.1  christos 	}
     80  1.1  christos       else
     81  1.1  christos 	{
     82  1.1  christos 	  /* Really link this block back into the free list.  */
     83  1.1  christos 	  _heapinfo[block].free.size = _heapinfo[block].busy.info.size;
     84  1.1  christos 	  _heapinfo[block].free.next = _heapinfo[i].free.next;
     85  1.1  christos 	  _heapinfo[block].free.prev = i;
     86  1.1  christos 	  _heapinfo[i].free.next = block;
     87  1.1  christos 	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
     88  1.1  christos 	  ++_chunks_free;
     89  1.1  christos 	}
     90  1.1  christos 
     91  1.1  christos       /* Now that the block is linked in, see if we can coalesce it
     92  1.1  christos 	 with its successor (by deleting its successor from the list
     93  1.1  christos 	 and adding in its size).  */
     94  1.1  christos       if (block + _heapinfo[block].free.size == _heapinfo[block].free.next)
     95  1.1  christos 	{
     96  1.1  christos 	  _heapinfo[block].free.size
     97  1.1  christos 	    += _heapinfo[_heapinfo[block].free.next].free.size;
     98  1.1  christos 	  _heapinfo[block].free.next
     99  1.1  christos 	    = _heapinfo[_heapinfo[block].free.next].free.next;
    100  1.1  christos 	  _heapinfo[_heapinfo[block].free.next].free.prev = block;
    101  1.1  christos 	  --_chunks_free;
    102  1.1  christos 	}
    103  1.1  christos 
    104  1.1  christos       /* Now see if we can return stuff to the system.  */
    105  1.1  christos       blocks = _heapinfo[block].free.size;
    106  1.1  christos       if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit
    107  1.1  christos 	  && (*__morecore) (0) == ADDRESS (block + blocks))
    108  1.1  christos 	{
    109  1.1  christos 	  register __malloc_size_t bytes = blocks * BLOCKSIZE;
    110  1.1  christos 	  _heaplimit -= blocks;
    111  1.1  christos 	  (*__morecore) (-bytes);
    112  1.1  christos 	  _heapinfo[_heapinfo[block].free.prev].free.next
    113  1.1  christos 	    = _heapinfo[block].free.next;
    114  1.1  christos 	  _heapinfo[_heapinfo[block].free.next].free.prev
    115  1.1  christos 	    = _heapinfo[block].free.prev;
    116  1.1  christos 	  block = _heapinfo[block].free.prev;
    117  1.1  christos 	  --_chunks_free;
    118  1.1  christos 	  _bytes_free -= bytes;
    119  1.1  christos 	}
    120  1.1  christos 
    121  1.1  christos       /* Set the next search to begin at this block.  */
    122  1.1  christos       _heapindex = block;
    123  1.1  christos       break;
    124  1.1  christos 
    125  1.1  christos     default:
    126  1.1  christos       /* Do some of the statistics.  */
    127  1.1  christos       --_chunks_used;
    128  1.1  christos       _bytes_used -= 1 << type;
    129  1.1  christos       ++_chunks_free;
    130  1.1  christos       _bytes_free += 1 << type;
    131  1.1  christos 
    132  1.1  christos       /* Get the address of the first free fragment in this block.  */
    133  1.1  christos       prev = (struct list *) ((char *) ADDRESS (block) +
    134  1.1  christos 			   (_heapinfo[block].busy.info.frag.first << type));
    135  1.1  christos 
    136  1.1  christos       if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
    137  1.1  christos 	{
    138  1.1  christos 	  /* If all fragments of this block are free, remove them
    139  1.1  christos 	     from the fragment list and free the whole block.  */
    140  1.1  christos 	  next = prev;
    141  1.1  christos 	  for (i = 1; i < (__malloc_size_t) (BLOCKSIZE >> type); ++i)
    142  1.1  christos 	    next = next->next;
    143  1.1  christos 	  prev->prev->next = next;
    144  1.1  christos 	  if (next != NULL)
    145  1.1  christos 	    next->prev = prev->prev;
    146  1.1  christos 	  _heapinfo[block].busy.type = 0;
    147  1.1  christos 	  _heapinfo[block].busy.info.size = 1;
    148  1.1  christos 
    149  1.1  christos 	  /* Keep the statistics accurate.  */
    150  1.1  christos 	  ++_chunks_used;
    151  1.1  christos 	  _bytes_used += BLOCKSIZE;
    152  1.1  christos 	  _chunks_free -= BLOCKSIZE >> type;
    153  1.1  christos 	  _bytes_free -= BLOCKSIZE;
    154  1.1  christos 
    155  1.1  christos 	  free (ADDRESS (block));
    156  1.1  christos 	}
    157  1.1  christos       else if (_heapinfo[block].busy.info.frag.nfree != 0)
    158  1.1  christos 	{
    159  1.1  christos 	  /* If some fragments of this block are free, link this
    160  1.1  christos 	     fragment into the fragment list after the first free
    161  1.1  christos 	     fragment of this block. */
    162  1.1  christos 	  next = (struct list *) ptr;
    163  1.1  christos 	  next->next = prev->next;
    164  1.1  christos 	  next->prev = prev;
    165  1.1  christos 	  prev->next = next;
    166  1.1  christos 	  if (next->next != NULL)
    167  1.1  christos 	    next->next->prev = next;
    168  1.1  christos 	  ++_heapinfo[block].busy.info.frag.nfree;
    169  1.1  christos 	}
    170  1.1  christos       else
    171  1.1  christos 	{
    172  1.1  christos 	  /* No fragments of this block are free, so link this
    173  1.1  christos 	     fragment into the fragment list and announce that
    174  1.1  christos 	     it is the first free fragment of this block. */
    175  1.1  christos 	  prev = (struct list *) ptr;
    176  1.1  christos 	  _heapinfo[block].busy.info.frag.nfree = 1;
    177  1.1  christos 	  _heapinfo[block].busy.info.frag.first = (unsigned long int)
    178  1.1  christos 	    ((unsigned long int) ((char *) ptr - (char *) NULL)
    179  1.1  christos 	     % BLOCKSIZE >> type);
    180  1.1  christos 	  prev->next = _fraghead[type].next;
    181  1.1  christos 	  prev->prev = &_fraghead[type];
    182  1.1  christos 	  prev->prev->next = prev;
    183  1.1  christos 	  if (prev->next != NULL)
    184  1.1  christos 	    prev->next->prev = prev;
    185  1.1  christos 	}
    186  1.1  christos       break;
    187  1.1  christos     }
    188  1.1  christos }
    189  1.1  christos 
    190  1.1  christos /* Return memory to the heap.  */
    191  1.1  christos void
    192  1.1  christos free (ptr)
    193  1.1  christos      __ptr_t ptr;
    194  1.1  christos {
    195  1.1  christos   register struct alignlist *l;
    196  1.1  christos 
    197  1.1  christos   if (ptr == NULL)
    198  1.1  christos     return;
    199  1.1  christos 
    200  1.1  christos   for (l = _aligned_blocks; l != NULL; l = l->next)
    201  1.1  christos     if (l->aligned == ptr)
    202  1.1  christos       {
    203  1.1  christos 	l->aligned = NULL;	/* Mark the slot in the list as free.  */
    204  1.1  christos 	ptr = l->exact;
    205  1.1  christos 	break;
    206  1.1  christos       }
    207  1.1  christos 
    208  1.1  christos   if (__free_hook != NULL)
    209  1.1  christos     (*__free_hook) (ptr);
    210  1.1  christos   else
    211  1.1  christos     _free_internal (ptr);
    212  1.1  christos }
    213