Home | History | Annotate | Line # | Download | only in dist
realloc.c revision 1.1.1.1
      1  1.1  christos /*	$NetBSD: realloc.c,v 1.1.1.1 2016/01/13 21:42:18 christos Exp $	*/
      2  1.1  christos 
      3  1.1  christos /* Change the size of a block allocated by `malloc'.
      4  1.1  christos    Copyright 1990, 1991, 1992, 1993, 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 #if  (defined (MEMMOVE_MISSING) || \
     31  1.1  christos       !defined(_LIBC) && !defined(STDC_HEADERS) && !defined(USG))
     32  1.1  christos 
     33  1.1  christos /* Snarfed directly from Emacs src/dispnew.c:
     34  1.1  christos    XXX Should use system bcopy if it handles overlap.  */
     35  1.1  christos #ifndef emacs
     36  1.1  christos 
     37  1.1  christos /* Like bcopy except never gets confused by overlap.  */
     38  1.1  christos 
     39  1.1  christos static void
     40  1.1  christos safe_bcopy (from, to, size)
     41  1.1  christos      char *from, *to;
     42  1.1  christos      int size;
     43  1.1  christos {
     44  1.1  christos   if (size <= 0 || from == to)
     45  1.1  christos     return;
     46  1.1  christos 
     47  1.1  christos   /* If the source and destination don't overlap, then bcopy can
     48  1.1  christos      handle it.  If they do overlap, but the destination is lower in
     49  1.1  christos      memory than the source, we'll assume bcopy can handle that.  */
     50  1.1  christos   if (to < from || from + size <= to)
     51  1.1  christos     bcopy (from, to, size);
     52  1.1  christos 
     53  1.1  christos   /* Otherwise, we'll copy from the end.  */
     54  1.1  christos   else
     55  1.1  christos     {
     56  1.1  christos       register char *endf = from + size;
     57  1.1  christos       register char *endt = to + size;
     58  1.1  christos 
     59  1.1  christos       /* If TO - FROM is large, then we should break the copy into
     60  1.1  christos 	 nonoverlapping chunks of TO - FROM bytes each.  However, if
     61  1.1  christos 	 TO - FROM is small, then the bcopy function call overhead
     62  1.1  christos 	 makes this not worth it.  The crossover point could be about
     63  1.1  christos 	 anywhere.  Since I don't think the obvious copy loop is too
     64  1.1  christos 	 bad, I'm trying to err in its favor.  */
     65  1.1  christos       if (to - from < 64)
     66  1.1  christos 	{
     67  1.1  christos 	  do
     68  1.1  christos 	    *--endt = *--endf;
     69  1.1  christos 	  while (endf != from);
     70  1.1  christos 	}
     71  1.1  christos       else
     72  1.1  christos 	{
     73  1.1  christos 	  for (;;)
     74  1.1  christos 	    {
     75  1.1  christos 	      endt -= (to - from);
     76  1.1  christos 	      endf -= (to - from);
     77  1.1  christos 
     78  1.1  christos 	      if (endt < to)
     79  1.1  christos 		break;
     80  1.1  christos 
     81  1.1  christos 	      bcopy (endf, endt, to - from);
     82  1.1  christos 	    }
     83  1.1  christos 
     84  1.1  christos 	  /* If SIZE wasn't a multiple of TO - FROM, there will be a
     85  1.1  christos 	     little left over.  The amount left over is
     86  1.1  christos 	     (endt + (to - from)) - to, which is endt - from.  */
     87  1.1  christos 	  bcopy (from, to, endt - from);
     88  1.1  christos 	}
     89  1.1  christos     }
     90  1.1  christos }
     91  1.1  christos #endif	/* Not emacs.  */
     92  1.1  christos 
     93  1.1  christos #define memmove(to, from, size) safe_bcopy ((from), (to), (size))
     94  1.1  christos 
     95  1.1  christos #endif
     96  1.1  christos 
     97  1.1  christos 
     98  1.1  christos #define min(A, B) ((A) < (B) ? (A) : (B))
     99  1.1  christos 
    100  1.1  christos /* Debugging hook for realloc.  */
    101  1.1  christos __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, __malloc_size_t __size));
    102  1.1  christos 
    103  1.1  christos /* Resize the given region to the new size, returning a pointer
    104  1.1  christos    to the (possibly moved) region.  This is optimized for speed;
    105  1.1  christos    some benchmarks seem to indicate that greater compactness is
    106  1.1  christos    achieved by unconditionally allocating and copying to a
    107  1.1  christos    new region.  This module has incestuous knowledge of the
    108  1.1  christos    internals of both free and malloc. */
    109  1.1  christos __ptr_t
    110  1.1  christos realloc (ptr, size)
    111  1.1  christos      __ptr_t ptr;
    112  1.1  christos      __malloc_size_t size;
    113  1.1  christos {
    114  1.1  christos   __ptr_t result;
    115  1.1  christos   int type;
    116  1.1  christos   __malloc_size_t block, blocks, oldlimit;
    117  1.1  christos 
    118  1.1  christos   if (size == 0)
    119  1.1  christos     {
    120  1.1  christos       free (ptr);
    121  1.1  christos       return malloc (0);
    122  1.1  christos     }
    123  1.1  christos   else if (ptr == NULL)
    124  1.1  christos     return malloc (size);
    125  1.1  christos 
    126  1.1  christos   if (__realloc_hook != NULL)
    127  1.1  christos     return (*__realloc_hook) (ptr, size);
    128  1.1  christos 
    129  1.1  christos   block = BLOCK (ptr);
    130  1.1  christos 
    131  1.1  christos   type = _heapinfo[block].busy.type;
    132  1.1  christos   switch (type)
    133  1.1  christos     {
    134  1.1  christos     case 0:
    135  1.1  christos       /* Maybe reallocate a large block to a small fragment.  */
    136  1.1  christos       if (size <= BLOCKSIZE / 2)
    137  1.1  christos 	{
    138  1.1  christos 	  result = malloc (size);
    139  1.1  christos 	  if (result != NULL)
    140  1.1  christos 	    {
    141  1.1  christos 	      memcpy (result, ptr, size);
    142  1.1  christos 	      _free_internal (ptr);
    143  1.1  christos 	      return result;
    144  1.1  christos 	    }
    145  1.1  christos 	}
    146  1.1  christos 
    147  1.1  christos       /* The new size is a large allocation as well;
    148  1.1  christos 	 see if we can hold it in place. */
    149  1.1  christos       blocks = BLOCKIFY (size);
    150  1.1  christos       if (blocks < _heapinfo[block].busy.info.size)
    151  1.1  christos 	{
    152  1.1  christos 	  /* The new size is smaller; return
    153  1.1  christos 	     excess memory to the free list. */
    154  1.1  christos 	  _heapinfo[block + blocks].busy.type = 0;
    155  1.1  christos 	  _heapinfo[block + blocks].busy.info.size
    156  1.1  christos 	    = _heapinfo[block].busy.info.size - blocks;
    157  1.1  christos 	  _heapinfo[block].busy.info.size = blocks;
    158  1.1  christos 	  /* We have just created a new chunk by splitting a chunk in two.
    159  1.1  christos 	     Now we will free this chunk; increment the statistics counter
    160  1.1  christos 	     so it doesn't become wrong when _free_internal decrements it.  */
    161  1.1  christos 	  ++_chunks_used;
    162  1.1  christos 	  _free_internal (ADDRESS (block + blocks));
    163  1.1  christos 	  result = ptr;
    164  1.1  christos 	}
    165  1.1  christos       else if (blocks == _heapinfo[block].busy.info.size)
    166  1.1  christos 	/* No size change necessary.  */
    167  1.1  christos 	result = ptr;
    168  1.1  christos       else
    169  1.1  christos 	{
    170  1.1  christos 	  /* Won't fit, so allocate a new region that will.
    171  1.1  christos 	     Free the old region first in case there is sufficient
    172  1.1  christos 	     adjacent free space to grow without moving. */
    173  1.1  christos 	  blocks = _heapinfo[block].busy.info.size;
    174  1.1  christos 	  /* Prevent free from actually returning memory to the system.  */
    175  1.1  christos 	  oldlimit = _heaplimit;
    176  1.1  christos 	  _heaplimit = 0;
    177  1.1  christos 	  _free_internal (ptr);
    178  1.1  christos 	  _heaplimit = oldlimit;
    179  1.1  christos 	  result = malloc (size);
    180  1.1  christos 	  if (result == NULL)
    181  1.1  christos 	    {
    182  1.1  christos 	      /* Now we're really in trouble.  We have to unfree
    183  1.1  christos 		 the thing we just freed.  Unfortunately it might
    184  1.1  christos 		 have been coalesced with its neighbors.  */
    185  1.1  christos 	      if (_heapindex == block)
    186  1.1  christos 	        (void) malloc (blocks * BLOCKSIZE);
    187  1.1  christos 	      else
    188  1.1  christos 		{
    189  1.1  christos 		  __ptr_t previous = malloc ((block - _heapindex) * BLOCKSIZE);
    190  1.1  christos 		  (void) malloc (blocks * BLOCKSIZE);
    191  1.1  christos 		  _free_internal (previous);
    192  1.1  christos 		}
    193  1.1  christos 	      return NULL;
    194  1.1  christos 	    }
    195  1.1  christos 	  if (ptr != result)
    196  1.1  christos 	    memmove (result, ptr, blocks * BLOCKSIZE);
    197  1.1  christos 	}
    198  1.1  christos       break;
    199  1.1  christos 
    200  1.1  christos     default:
    201  1.1  christos       /* Old size is a fragment; type is logarithm
    202  1.1  christos 	 to base two of the fragment size.  */
    203  1.1  christos       if (size > (__malloc_size_t) (1 << (type - 1)) &&
    204  1.1  christos 	  size <= (__malloc_size_t) (1 << type))
    205  1.1  christos 	/* The new size is the same kind of fragment.  */
    206  1.1  christos 	result = ptr;
    207  1.1  christos       else
    208  1.1  christos 	{
    209  1.1  christos 	  /* The new size is different; allocate a new space,
    210  1.1  christos 	     and copy the lesser of the new size and the old. */
    211  1.1  christos 	  result = malloc (size);
    212  1.1  christos 	  if (result == NULL)
    213  1.1  christos 	    return NULL;
    214  1.1  christos 	  memcpy (result, ptr, min (size, (__malloc_size_t) 1 << type));
    215  1.1  christos 	  free (ptr);
    216  1.1  christos 	}
    217  1.1  christos       break;
    218  1.1  christos     }
    219  1.1  christos 
    220  1.1  christos   return result;
    221  1.1  christos }
    222