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
#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 == 0
-#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;
-
-/* File descriptor for mmap. If we don't have anonymous mapping,
- /dev/zero will be opened on it. */
-
-static int mmap_fd;
-
-/* Temporary storage for mmap_set_vars, see there. */
-
-static struct mmap_region *mmap_regions_1;
-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));
-
-
-/* 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 = 0;
-
- 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));
- else
- {
- r->nbytes_mapped -= nbytes;
- success = 1;
- }
- }
- else if (npages > 0)
- {
- struct mmap_region *r2;
-
- 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. */
- r2 = mmap_find (region_end, region_end + nbytes);
- if (r2 == NULL)
- {
- 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));
- 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));
- }
- else
- {
- r->nbytes_mapped += nbytes;
- success = 1;
- }
- }
- }
-
- 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;
-
- if (restore_p)
- {
- mmap_regions = mmap_regions_1;
- mmap_fd = mmap_fd_1;
- for (r = mmap_regions; r; r = r->next)
- *r->var = MMAP_USER_AREA (r);
- }
- else
- {
- for (r = mmap_regions; r; r = r->next)
- *r->var = NULL;
- mmap_regions_1 = mmap_regions;
- mmap_regions = NULL;
- mmap_fd_1 = mmap_fd;
- 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;
-
- r_alloc_init ();
-
- 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;
-
- r_alloc_init ();
-
- 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;
-{
- r_alloc_init ();
-
- if (*var)
- {
- mmap_free (MMAP_REGION (*var));
- *var = NULL;
- }
-}
-
-#endif /* REL_ALLOC_MMAP */
-
\f
/***********************************************************************
static void
r_alloc_init ()
{
-#if defined REL_ALLOC_MMAP && MAP_ANON == 0
- /* The value of mmap_fd is initially 0 in temacs, and -1
- in a dumped Emacs. */
- if (mmap_fd <= 0)
- {
- /* No anonymous mmap -- we need the file descriptor. */
- mmap_fd = open ("/dev/zero", O_RDONLY);
- if (mmap_fd == -1)
- fatal ("Cannot open /dev/zero: %s", emacs_strerror (errno));
- }
-#endif /* REL_ALLOC_MMAP && MAP_ANON == 0 */
-
if (r_alloc_initialized)
return;
r_alloc_initialized = 1;
-#if defined REL_ALLOC_MMAP && MAP_ANON != 0
- mmap_fd = -1;
-#endif
page_size = PAGE;
#ifndef SYSTEM_MALLOC