| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100 | /* * libc/stdlib/malloc/realloc.c -- realloc function * *  Copyright (C) 2002  NEC Corporation *  Copyright (C) 2002  Miles Bader <miles@gnu.org> * * This file is subject to the terms and conditions of the GNU Lesser * General Public License.  See the file COPYING.LIB in the main * directory of this archive for more details. * * Written by Miles Bader <miles@gnu.org> */#include <stdlib.h>#include <string.h>#include <errno.h>#include "malloc.h"#include "heap.h"void *realloc (void *mem, size_t new_size){  size_t size;  char *base_mem;  /* Check for special cases.  */  if (! new_size)    {      free (mem);      return malloc (new_size);    }  if (! mem)    return malloc (new_size);  /* This matches the check in malloc() */  if (unlikely(((unsigned long)new_size > (unsigned long)(MALLOC_HEADER_SIZE*-2))))    return NULL;  /* Normal realloc.  */  base_mem = MALLOC_BASE (mem);  size = MALLOC_SIZE (mem);  /* Include extra space to record the size of the allocated block.     Also make sure that we're dealing in a multiple of the heap     allocation unit (SIZE is already guaranteed to be so).*/  new_size = HEAP_ADJUST_SIZE (new_size + MALLOC_HEADER_SIZE);  if (new_size < sizeof (struct heap_free_area))    /* Because we sometimes must use a freed block to hold a free-area node,       we must make sure that every allocated block can hold one.  */    new_size = HEAP_ADJUST_SIZE (sizeof (struct heap_free_area));  MALLOC_DEBUG (1, "realloc: 0x%lx, %d (base = 0x%lx, total_size = %d)",		(long)mem, new_size, (long)base_mem, size);  if (new_size > size)    /* Grow the block.  */    {      size_t extra = new_size - size;      __heap_lock (&__malloc_heap_lock);      extra = __heap_alloc_at (&__malloc_heap, base_mem + size, extra);      __heap_unlock (&__malloc_heap_lock);      if (extra)	/* Record the changed size.  */	MALLOC_SET_SIZE (base_mem, size + extra);      else	/* Our attempts to extend MEM in place failed, just	   allocate-and-copy.  */	{	  void *new_mem = malloc (new_size - MALLOC_HEADER_SIZE);	  if (new_mem)	    {	      memcpy (new_mem, mem, size - MALLOC_HEADER_SIZE);	      free (mem);	    }	  mem = new_mem;	}    }  else if (new_size + MALLOC_REALLOC_MIN_FREE_SIZE <= size)    /* Shrink the block.  */    {      __heap_lock (&__malloc_heap_lock);      __heap_free (&__malloc_heap, base_mem + new_size, size - new_size);      __heap_unlock (&__malloc_heap_lock);      MALLOC_SET_SIZE (base_mem, new_size);    }  if (mem)    MALLOC_DEBUG (-1, "realloc: returning 0x%lx (base:0x%lx, total_size:%d)",		  (long)mem, (long)MALLOC_BASE(mem), (long)MALLOC_SIZE(mem));  else    MALLOC_DEBUG (-1, "realloc: returning 0");  return mem;}
 |