]> code.delx.au - gnu-emacs/blobdiff - src/ralloc.c
(archive-l-e): New optional argument `float' means generate a float value.
[gnu-emacs] / src / ralloc.c
index f6ae887f4c1cf8796736f560841002ab7273fb91..fea9ea5d0a81f3cf18aa5e33fa4a943b822d9ffc 100644 (file)
@@ -1,5 +1,6 @@
-/* Block-relocating memory allocator. 
-   Copyright (C) 1993, 1995, 2000 Free Software Foundation, Inc.
+/* Block-relocating memory allocator.
+   Copyright (C) 1993, 1995, 2000, 2002, 2003, 2004,
+                 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -15,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 /* NOTES:
 
@@ -28,6 +29,7 @@ Boston, MA 02111-1307, USA.  */
 
 #include <config.h>
 #include "lisp.h"              /* Needed for VALBITS.  */
+#include "blockinput.h"
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -42,11 +44,11 @@ typedef size_t SIZE;
 extern void safe_bcopy ();
 
 #ifdef DOUG_LEA_MALLOC
-#define M_TOP_PAD           -2 
+#define M_TOP_PAD           -2
 extern int mallopt ();
 #else /* not DOUG_LEA_MALLOC */
 #ifndef SYSTEM_MALLOC
-extern int __malloc_extra_blocks;
+extern size_t __malloc_extra_blocks;
 #endif /* SYSTEM_MALLOC */
 #endif /* not DOUG_LEA_MALLOC */
 
@@ -98,7 +100,7 @@ static POINTER break_value;
 /* This is the size of a page.  We round memory requests to this boundary.  */
 static int page_size;
 
-/* Whenever we get memory from the system, get this many extra bytes.  This 
+/* Whenever we get memory from the system, get this many extra bytes.  This
    must be a multiple of page_size.  */
 static int extra_bytes;
 
@@ -114,6 +116,14 @@ static int extra_bytes;
 #define MEM_ROUNDUP(addr) (((unsigned long int)(addr) + MEM_ALIGN - 1) \
                                   & ~(MEM_ALIGN - 1))
 
+/* The hook `malloc' uses for the function which gets more space
+   from the system.  */
+
+#ifndef SYSTEM_MALLOC
+extern POINTER (*__morecore) ();
+#endif
+
+
 \f
 /***********************************************************************
                      Implementation using sbrk
@@ -133,7 +143,7 @@ static int extra_bytes;
    We try to make just one heap and make it larger as necessary.
    But sometimes we can't do that, because we can't get contiguous
    space to add onto the heap.  When that happens, we start a new heap.  */
-   
+
 typedef struct heap
 {
   struct heap *next;
@@ -166,7 +176,7 @@ static heap_ptr first_heap, last_heap;
 /* These structures are allocated in the malloc arena.
    The linked list is kept in order of increasing '.data' members.
    The data blocks abut each other; if b->next is non-nil, then
-   b->data + b->size == b->next->data.  
+   b->data + b->size == b->next->data.
 
    An element with variable==NIL denotes a freed block, which has not yet
    been collected.  They may only appear while r_alloc_freeze > 0, and will be
@@ -459,8 +469,8 @@ get_bloc (size)
 /* Calculate new locations of blocs in the list beginning with BLOC,
    relocating it to start at ADDRESS, in heap HEAP.  If enough space is
    not presently available in our reserve, call obtain for
-   more space. 
-   
+   more space.
+
    Store the new location of each bloc in its new_data field.
    Do not touch the contents of blocs or break_value.  */
 
@@ -473,7 +483,7 @@ relocate_blocs (bloc, heap, address)
   register bloc_ptr b = bloc;
 
   /* No need to ever call this if arena is frozen, bug somewhere!  */
-  if (r_alloc_freeze_level) 
+  if (r_alloc_freeze_level)
     abort();
 
   while (b)
@@ -498,7 +508,7 @@ relocate_blocs (bloc, heap, address)
          /* Add up the size of all the following blocs.  */
          while (tb != NIL_BLOC)
            {
-             if (tb->variable) 
+             if (tb->variable)
                s += tb->size;
 
              tb = tb->next;
@@ -515,7 +525,7 @@ relocate_blocs (bloc, heap, address)
       /* Record the new address of this bloc
         and update where the next bloc can start.  */
       b->new_data = address;
-      if (b->variable) 
+      if (b->variable)
        address = (char *) address + b->size;
       b = b->next;
     }
@@ -631,7 +641,7 @@ resize_bloc (bloc, size)
   SIZE old_size;
 
   /* No need to ever call this if arena is frozen, bug somewhere!  */
-  if (r_alloc_freeze_level) 
+  if (r_alloc_freeze_level)
     abort();
 
   if (bloc == NIL_BLOC || size == bloc->size)
@@ -673,8 +683,8 @@ resize_bloc (bloc, size)
            {
              b->size = 0;
              b->data = b->new_data;
-            } 
-         else 
+            }
+         else
            {
              safe_bcopy (b->data, b->new_data, b->size);
              *b->variable = b->data = b->new_data;
@@ -700,8 +710,8 @@ resize_bloc (bloc, size)
            {
              b->size = 0;
              b->data = b->new_data;
-            } 
-         else 
+            }
+         else
            {
              safe_bcopy (b->data, b->new_data, b->size);
              *b->variable = b->data = b->new_data;
@@ -730,7 +740,7 @@ free_bloc (bloc)
       bloc->variable = (POINTER *) NIL;
       return;
     }
-  
+
   resize_bloc (bloc, 0);
 
   if (bloc == first_bloc && bloc == last_bloc)
@@ -786,7 +796,7 @@ free_bloc (bloc)
    __morecore hook values - in particular, __default_morecore in the
    GNU malloc package.  */
 
-POINTER 
+POINTER
 r_alloc_sbrk (size)
      long size;
 {
@@ -842,7 +852,7 @@ r_alloc_sbrk (size)
       if (first_heap->bloc_start < new_bloc_start)
        {
          /* This is no clean solution - no idea how to do it better.  */
-         if (r_alloc_freeze_level) 
+         if (r_alloc_freeze_level)
            return NIL;
 
          /* There is a bug here: if the above obtain call succeeded, but the
@@ -926,7 +936,6 @@ r_alloc_sbrk (size)
   return address;
 }
 
-#ifndef REL_ALLOC_MMAP
 
 /* Allocate a relocatable bloc of storage of size SIZE.  A pointer to
    the data is returned in *PTR.  PTR is thus the address of some variable
@@ -1011,7 +1020,7 @@ r_re_alloc (ptr, size)
 
   if (!*ptr)
     return r_alloc (ptr, size);
-  if (!size) 
+  if (!size)
     {
       r_alloc_free (ptr);
       return r_alloc (ptr, 0);
@@ -1021,12 +1030,12 @@ r_re_alloc (ptr, size)
   if (bloc == NIL_BLOC)
     abort ();
 
-  if (size < bloc->size) 
+  if (size < bloc->size)
     {
       /* Wouldn't it be useful to actually resize the bloc here?  */
       /* I think so too, but not if it's too expensive...  */
-      if ((bloc->size - MEM_ROUNDUP (size) >= page_size) 
-          && r_alloc_freeze_level == 0) 
+      if ((bloc->size - MEM_ROUNDUP (size) >= page_size)
+          && r_alloc_freeze_level == 0)
        {
          resize_bloc (bloc, MEM_ROUNDUP (size));
          /* Never mind if this fails, just do nothing...  */
@@ -1048,7 +1057,7 @@ r_re_alloc (ptr, size)
           else
            return NIL;
        }
-      else 
+      else
        {
          if (! resize_bloc (bloc, MEM_ROUNDUP (size)))
            return NIL;
@@ -1084,22 +1093,22 @@ void
 r_alloc_thaw ()
 {
 
-  if (! r_alloc_initialized) 
+  if (! r_alloc_initialized)
     r_alloc_init ();
 
   if (--r_alloc_freeze_level < 0)
     abort ();
 
-  /* This frees all unused blocs.  It is not too inefficient, as the resize 
-     and bcopy is done only once.  Afterwards, all unreferenced blocs are 
+  /* This frees all unused blocs.  It is not too inefficient, as the resize
+     and bcopy is done only once.  Afterwards, all unreferenced blocs are
      already shrunk to zero size.  */
-  if (!r_alloc_freeze_level) 
+  if (!r_alloc_freeze_level)
     {
       bloc_ptr *b = &first_bloc;
-      while (*b) 
-       if (!(*b)->variable) 
-         free_bloc (*b); 
-       else 
+      while (*b)
+       if (!(*b)->variable)
+         free_bloc (*b);
+       else
          b = &(*b)->next;
     }
 }
@@ -1217,454 +1226,12 @@ r_alloc_check ()
 
 #endif /* DEBUG */
 
-#endif /* not REL_ALLOC_MMAP */
-
-\f
-/***********************************************************************
-                    Implementation based on mmap
- ***********************************************************************/
-
-#ifdef REL_ALLOC_MMAP
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#ifndef MAP_ANON
-#ifdef MAP_ANONYMOUS
-#define MAP_ANON MAP_ANONYMOUS
-#else
-#define MAP_ANON 0
-#endif
-#endif
-#include <stdio.h>
-#include <errno.h>
-#if !MAP_ANON
-#include <fcntl.h>
-#endif
-
-/* Memory is allocated in regions which are mapped using mmap(2).
-   The current implementation lets the system select mapped
-   addresses;  we're not using MAP_FIXED in general, except when
-   trying to enlarge regions.
-
-   Each mapped region starts with a mmap_region structure, the user
-   area starts after that structure, aligned to MEM_ALIGN.
-
-       +-----------------------+
-       | struct mmap_info +    |
-       | padding               |
-       +-----------------------+
-       | user data             |
-       |                       |
-       |                       |
-       +-----------------------+  */
-
-struct mmap_region
-{
-  /* User-specified size.  */
-  size_t nbytes_specified;
-  
-  /* Number of bytes mapped */
-  size_t nbytes_mapped;
-
-  /* Pointer to the location holding the address of the memory
-     allocated with the mmap'd block.  The variable actually points
-     after this structure.  */
-  POINTER_TYPE **var;
-
-  /* Next and previous in list of all mmap'd regions.  */
-  struct mmap_region *next, *prev;
-};
-
-/* Doubly-linked list of mmap'd regions.  */
-
-static struct mmap_region *mmap_regions;
-
-/* Temporary storage for mmap_set_vars, see there.  */
-
-static struct mmap_region *mmap_regions_1;
-
-/* File descriptor for mmap.  If we don't have anonymous mapping,
-   /dev/zero will be opened on it.  */
-
-static int mmap_fd = -1;
-
-/* Value is X rounded up to the next multiple of N.  */
-
-#define ROUND(X, N)    (((X) + (N) - 1) / (N) * (N))
-
-/* Size of mmap_region structure plus padding.  */
-
-#define MMAP_REGION_STRUCT_SIZE        \
-     ROUND (sizeof (struct mmap_region), MEM_ALIGN)
-
-/* Given a pointer P to the start of the user-visible part of a mapped
-   region, return a pointer to the start of the region.  */
-
-#define MMAP_REGION(P) \
-     ((struct mmap_region *) ((char *) (P) - MMAP_REGION_STRUCT_SIZE))
-
-/* Given a pointer P to the start of a mapped region, return a pointer
-   to the start of the user-visible part of the region.  */
-
-#define MMAP_USER_AREA(P) \
-     ((POINTER_TYPE *) ((char *) (P) + MMAP_REGION_STRUCT_SIZE))
-
-/* Function prototypes.  */
-
-static int mmap_free P_ ((struct mmap_region *));
-static int mmap_enlarge P_ ((struct mmap_region *, int));
-static struct mmap_region *mmap_find P_ ((POINTER_TYPE *, POINTER_TYPE *));
-POINTER_TYPE *r_alloc P_ ((POINTER_TYPE **, size_t));
-POINTER_TYPE *r_re_alloc P_ ((POINTER_TYPE **, size_t));
-void r_alloc_free P_ ((POINTER_TYPE **ptr));
-
-
-void
-r_alloc_init_fd ()
-{
-  /* No anonymous mmap -- we need the file descriptor.  */
-  mmap_fd = open ("/dev/zero", O_RDONLY);
-  if (mmap_fd < 0)
-    fatal ("cannot open /dev/zero");
-}
-
-/* Return a region overlapping address range START...END, or null if
-   none.  END is not including, i.e. the last byte in the range
-   is at END - 1.  */
-
-static struct mmap_region *
-mmap_find (start, end)
-     POINTER_TYPE *start, *end;
-{
-  struct mmap_region *r;
-  char *s = (char *) start, *e = (char *) end;
-  
-  for (r = mmap_regions; r; r = r->next)
-    {
-      char *rstart = (char *) r;
-      char *rend   = rstart + r->nbytes_mapped;
-
-      if (/* First byte of range, i.e. START, in this region?  */
-         (s >= rstart && s < rend)
-         /* Last byte of range, i.e. END - 1, in this region?  */
-         || (e > rstart && e <= rend)
-         /* First byte of this region in the range?  */
-         || (rstart >= s && rstart < e)
-         /* Last byte of this region in the range?  */
-         || (rend > s && rend <= e))
-       break;
-    }
-
-  return r;
-}
-
-
-/* Unmap a region.  P is a pointer to the start of the user-araa of
-   the region.  Value is non-zero if successful.  */
-
-static int
-mmap_free (r)
-     struct mmap_region *r;
-{
-  if (r->next)
-    r->next->prev = r->prev;
-  if (r->prev)
-    r->prev->next = r->next;
-  else
-    mmap_regions = r->next;
-  
-  if (munmap (r, r->nbytes_mapped) == -1)
-    {
-      fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
-      return 0;
-    }
-
-  return 1;
-}
-
-
-/* Enlarge region R by NPAGES pages.  NPAGES < 0 means shrink R.
-   Value is non-zero if successful.  */
-
-static int
-mmap_enlarge (r, npages)
-     struct mmap_region *r;
-     int npages;
-{
-  char *region_end = (char *) r + r->nbytes_mapped;
-  size_t nbytes;
-  int success = 1;
-
-  if (npages < 0)
-    {
-      /* Unmap pages at the end of the region.  */
-      nbytes = - npages * page_size;
-      if (munmap (region_end - nbytes, nbytes) == -1)
-       {
-         fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
-         success = 0;
-       }
-      else
-       r->nbytes_mapped -= nbytes;
-    }
-  else if (npages > 0)
-    {
-      nbytes = npages * page_size;
-      
-      /* Try to map additional pages at the end of the region.  We
-        cannot do this if the address range is already occupied by
-        something else because mmap deletes any previous mapping.
-        I'm not sure this is worth doing, let's see.  */
-      if (mmap_find (region_end, region_end + nbytes))
-       success = 0;
-      else
-       {
-         POINTER_TYPE *p;
-      
-         p = mmap (region_end, nbytes, PROT_READ | PROT_WRITE,
-                   MAP_ANON | MAP_PRIVATE | MAP_FIXED, mmap_fd, 0);
-         if (p == MAP_FAILED)
-           {
-             fprintf (stderr, "mmap: %s\n", emacs_strerror (errno));
-             success = 0;
-           }
-         else if (p != (POINTER_TYPE *) region_end)
-           {
-             /* Kernels are free to choose a different address.  In
-                that case, unmap what we've mapped above; we have
-                no use for it.  */
-             if (munmap (p, nbytes) == -1)
-               fprintf (stderr, "munmap: %s\n", emacs_strerror (errno));
-             success = 0;
-           }
-         else
-           r->nbytes_mapped += nbytes;
-       }
-      
-      success = 0;
-    }
-
-  return success;
-}
-
-
-/* Set or reset variables holding references to mapped regions.  If
-   RESTORE_P is zero, set all variables to null.  If RESTORE_P is
-   non-zero, set all variables to the start of the user-areas
-   of mapped regions.
-
-   This function is called from Fdump_emacs to ensure that the dumped
-   Emacs doesn't contain references to memory that won't be mapped
-   when Emacs starts.  */
-
-void
-mmap_set_vars (restore_p)
-     int restore_p;
-{
-  struct mmap_region *r;
-  static int fd;
-
-  if (restore_p)
-    {
-      mmap_regions = mmap_regions_1;
-      for (r = mmap_regions; r; r = r->next)
-       *r->var = MMAP_USER_AREA (r);
-      mmap_fd = fd;
-    }
-  else
-    {
-      for (r = mmap_regions; r; r = r->next)
-       *r->var = NULL;
-      mmap_regions_1 = mmap_regions;
-      mmap_regions = NULL;
-      mmap_fd = -1;
-    }
-}
-
-
-/* Return total number of bytes mapped.  */
-
-size_t
-mmap_mapped_bytes ()
-{
-  struct mmap_region *r;
-  size_t n = 0;
-  
-  for (r = mmap_regions; r; r = r->next)
-    n += r->nbytes_mapped;
-
-  return n;
-}
-
-
-/* Allocate a block of storage large enough to hold NBYTES bytes of
-   data.  A pointer to the data is returned in *VAR.  VAR is thus the
-   address of some variable which will use the data area.
-
-   The allocation of 0 bytes is valid.
-
-   If we can't allocate the necessary memory, set *VAR to null, and
-   return null.  */
-
-POINTER_TYPE *
-r_alloc (var, nbytes)
-     POINTER_TYPE **var;
-     size_t nbytes;
-{
-  void *p;
-  size_t map;
-
-  if (!r_alloc_initialized)
-    r_alloc_init ();
-#if defined (REL_ALLOC_MMAP) && !MAP_ANON
-  if (mmap_fd == -1)
-    r_alloc_init_fd ();
-#endif
-
-  map = ROUND (nbytes + MMAP_REGION_STRUCT_SIZE, page_size);
-  p = mmap (NULL, map, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
-           mmap_fd, 0);
-  
-  if (p == MAP_FAILED)
-    {
-      if (errno != ENOMEM)
-       fprintf (stderr, "mmap: %s\n", emacs_strerror (errno));
-      p = NULL;
-    }
-  else
-    {
-      struct mmap_region *r = (struct mmap_region *) p;
-      
-      r->nbytes_specified = nbytes;
-      r->nbytes_mapped = map;
-      r->var = var;
-      r->prev = NULL;
-      r->next = mmap_regions;
-      if (r->next)
-       r->next->prev = r;
-      mmap_regions = r;
-      
-      p = MMAP_USER_AREA (p);
-    }
-  
-  return *var = p;
-}
-
-
-/* Given a pointer at address VAR to data allocated with r_alloc,
-   resize it to size NBYTES.  Change *VAR to reflect the new block,
-   and return this value.  If more memory cannot be allocated, then
-   leave *VAR unchanged, and return null.  */
-
-POINTER_TYPE *
-r_re_alloc (var, nbytes)
-     POINTER_TYPE **var;
-     size_t nbytes;
-{
-  POINTER_TYPE *result;
-  
-  if (!r_alloc_initialized)
-    r_alloc_init ();
-#if defined (REL_ALLOC_MMAP) && !MAP_ANON
-  if (mmap_fd == -1)
-    r_alloc_init_fd ();
-#endif
-
-  if (*var == NULL)
-    result = r_alloc (var, nbytes);
-  else if (nbytes == 0) 
-    {
-      r_alloc_free (var);
-      result = r_alloc (var, nbytes);
-    }
-  else
-    {
-      struct mmap_region *r = MMAP_REGION (*var);
-      size_t room = r->nbytes_mapped - MMAP_REGION_STRUCT_SIZE;
-      
-      if (room < nbytes)
-       {
-         /* Must enlarge.  */
-         POINTER_TYPE *old_ptr = *var;
-
-         /* Try to map additional pages at the end of the region.
-            If that fails, allocate a new region,  copy data
-            from the old region, then free it.  */
-         if (mmap_enlarge (r, ROUND (nbytes - room, page_size) / page_size))
-           {
-             r->nbytes_specified = nbytes;
-             *var = result = old_ptr;
-           }
-         else if (r_alloc (var, nbytes))
-           {
-             bcopy (old_ptr, *var, r->nbytes_specified);
-             mmap_free (MMAP_REGION (old_ptr));
-             result = *var;
-             r = MMAP_REGION (result);
-             r->nbytes_specified = nbytes;
-           }
-         else
-           {
-             *var = old_ptr;
-             result = NULL;
-           }
-       }
-      else if (room - nbytes >= page_size)
-       {
-         /* Shrinking by at least a page.  Let's give some
-            memory back to the system.  */
-         mmap_enlarge (r, - (room - nbytes) / page_size);
-         result = *var;
-         r->nbytes_specified = nbytes;
-       }
-      else
-       {
-         /* Leave it alone.  */
-         result = *var;
-         r->nbytes_specified = nbytes;
-       }
-    }
-
-  return result;
-}
-
-
-/* Free a block of relocatable storage whose data is pointed to by
-   PTR.  Store 0 in *PTR to show there's no block allocated.  */
-
-void
-r_alloc_free (var)
-     POINTER_TYPE **var;
-{
-  if (!r_alloc_initialized)
-    r_alloc_init ();
-#if defined (REL_ALLOC_MMAP) && !MAP_ANON
-  if (mmap_fd == -1)
-    r_alloc_init_fd ();
-#endif
-
-  if (*var)
-    {
-      mmap_free (MMAP_REGION (*var));
-      *var = NULL;
-    }
-}
-
-#endif /* REL_ALLOC_MMAP */
-
 
 \f
 /***********************************************************************
                            Initialization
  ***********************************************************************/
 
-/* The hook `malloc' uses for the function which gets more space
-   from the system.  */
-
-#ifndef SYSTEM_MALLOC
-extern POINTER (*__morecore) ();
-#endif
-
 /* Initialize various things for memory allocation.  */
 
 static void
@@ -1672,15 +1239,13 @@ r_alloc_init ()
 {
   if (r_alloc_initialized)
     return;
-
   r_alloc_initialized = 1;
+
   page_size = PAGE;
 #ifndef SYSTEM_MALLOC
   real_morecore = __morecore;
   __morecore = r_alloc_sbrk;
-#endif
 
-#ifndef REL_ALLOC_MMAP
   first_heap = last_heap = &heap_base;
   first_heap->next = first_heap->prev = NIL_HEAP;
   first_heap->start = first_heap->bloc_start
@@ -1692,7 +1257,9 @@ r_alloc_init ()
 #endif
 
 #ifdef DOUG_LEA_MALLOC
-    mallopt (M_TOP_PAD, 64 * 4096);
+  BLOCK_INPUT;
+  mallopt (M_TOP_PAD, 64 * 4096);
+  UNBLOCK_INPUT;
 #else
 #ifndef SYSTEM_MALLOC
   /* Give GNU malloc's morecore some hysteresis
@@ -1701,7 +1268,7 @@ r_alloc_init ()
 #endif
 #endif
 
-#ifndef REL_ALLOC_MMAP
+#ifndef SYSTEM_MALLOC
   first_heap->end = (POINTER) ROUNDUP (first_heap->start);
 
   /* The extra call to real_morecore guarantees that the end of the
@@ -1720,6 +1287,9 @@ r_alloc_init ()
         (char *) first_heap->end - (char *) first_heap->start);
   virtual_break_value = break_value = first_heap->bloc_start = first_heap->end;
 #endif
+
   use_relocatable_buffers = 1;
-  r_alloc_init_fd ();
 }
+
+/* arch-tag: 6a524a15-faff-44c8-95d4-a5da6f55110f
+   (do not change this comment) */