delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2000/07/28/04:26:26

Message-ID: <3981452C.AB1C2C0@softhome.net>
Date: Fri, 28 Jul 2000 10:32:44 +0200
From: Laurynas Biveinis <lauras AT softhome DOT net>
X-Mailer: Mozilla 4.73 [en] (Win98; U)
X-Accept-Language: lt,en
MIME-Version: 1.0
To: Alexandre Oliva <aoliva AT redhat DOT com>
CC: law AT cygnus DOT com, gcc-patches AT gcc DOT gnu DOT org, djgpp-workers AT delorie DOT com
Subject: New patch (Was: Re: PATCH: enabling ggc-page with simple malloc())
References: <18258 DOT 964726841 AT upchuck> <39809554 DOT 400D6AEB AT softhome DOT net> <or66prussb DOT fsf AT guarana DOT lsd DOT ic DOT unicamp DOT br>
Reply-To: djgpp-workers AT delorie DOT com

Alexandre Oliva wrote:
> Maybe you should post it here and let others comment on it? (assuming
> you haven't yet; I don't recall whether you'd Cc:ed the list)

OK, here we are. Note that this patch has been tested under DJGPP
only, it should be tested at least on two more platforms: with mmap() and
with valloc().

Also this patch does not include regenerated configure scripts, because
I can use only DJGPP port of Autoconf, which produces slightly different
scripts.

include/ChangeLog:
2000-06-18 Alexandre Oliva  <oliva AT lsd DOT ic DOT unicamp DOT br>
           Laurynas Biveinis <lauras AT softhome DOT net>
        
        * libiberty.h (xvalloc, xvfree, xvalloc_overhead): Declare.

libiberty/ChangeLog:
2000-06-18 Alexandre Oliva  <oliva AT lsd DOT ic DOT unicamp DOT br>
           Laurynas Biveinis <lauras AT softhome DOT net>
        
        * xvalloc.c: New file.
        * Makefile.in (CFILES): Added xvalloc.c.
        (REQUIRED_OFILES): Added xvalloc.o.
        (xvalloc.o): List dependencies.
        * configure.in: Auto-detect fcntl.h, sys/mman.h, MMAP_ANYWHERE and
        valloc.
        * configure, config.in: Rebuilt.

gcc/ChangeLog:
2000-06-18 Alexandre Oliva  <oliva AT lsd DOT ic DOT unicamp DOT br>
           Laurynas Biveinis <lauras AT softhome DOT net>
        
        * configure.in: No longer check for valloc.  Always use ggc-page.
        * configure, config.in: Rebuilt.
        * Makefile.in (ggc-page.o): Depend on libiberty.h
        * ggc-page.c (alloc_page): Use xvalloc from libiberty.
        (release_pages): Use xvfree.
        (struct globals): New member usable_pagesize.
        (init_ggc): Compute it with xvalloc_overhead from libiberty.
        (OBJECTS_PER_PAGE): Use it.
        (MISALIGNMENT): New macro.
        (clear_marks): Use it.
        (alloc_anon): Deleted.

Index: include/libiberty.h
===================================================================
RCS file: /cvs/gcc/egcs/include/libiberty.h,v
retrieving revision 1.12
diff -u -r1.12 libiberty.h
--- libiberty.h	2000/05/23 17:42:17	1.12
+++ libiberty.h	2000/07/28 08:10:57
@@ -161,6 +161,22 @@
 
 extern PTR xmemdup PARAMS ((const PTR, size_t, size_t)) ATTRIBUTE_MALLOC;
 
+/* Allocate a page-aligned memory block.  */
+
+extern char *xvalloc PARAMS ((size_t)) ATTRIBUTE_MALLOC;
+
+/* Release memory allocated by xvalloc.  */
+
+extern void xvfree PARAMS ((char *, size_t));
+
+/* Initialize xvalloc internal structures.  It's optional, but it's
+   best to call it before any memory allocation takes place.  It can
+   be called multiple times, returning how many bytes should be left
+   at the end of a page for memory-allocation data structures, so as
+   to avoid wasting every other page.  This value should be subtracted
+   from getpagesize() in the argument to xvalloc/xvfree. */
+extern unsigned xvalloc_overhead PARAMS ((void));
+
 /* hex character manipulation routines */
 
 #define _hex_array_size 256

Index: gcc/Makefile.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/Makefile.in,v
retrieving revision 1.484
diff -u -r1.484 Makefile.in
--- Makefile.in	2000/07/24 17:43:42	1.484
+++ Makefile.in	2000/07/28 07:24:22
@@ -1211,7 +1211,7 @@
 	$(GGC_H) varray.h $(TIMEVAR_H)
 
 ggc-page.o: ggc-page.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h toplev.h \
-	$(GGC_H) varray.h $(TIMEVAR_H)
+	$(GGC_H) varray.h $(TIMEVAR_H) $(srcdir)/../include/libiberty.h
 
 ggc-none.o: ggc-none.c $(CONFIG_H) $(RTL_H) $(GGC_H)
 
Index: gcc/config.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config.in,v
retrieving revision 1.77
diff -u -r1.77 config.in
--- config.in	2000/07/17 09:23:16	1.77
+++ config.in	2000/07/28 07:24:24
@@ -213,9 +213,6 @@
 /* Define if you have the sysconf function.  */
 #undef HAVE_SYSCONF
 
-/* Define if you have the valloc function.  */
-#undef HAVE_VALLOC
-
 /* Define if you have the <argz.h> header file.  */
 #undef HAVE_ARGZ_H
 
Index: gcc/configure.in
===================================================================
RCS file: /cvs/gcc/egcs/gcc/configure.in,v
retrieving revision 1.398
diff -u -r1.398 configure.in
--- configure.in	2000/07/17 20:55:43	1.398
+++ configure.in	2000/07/28 07:25:17
@@ -474,7 +474,7 @@
 AC_CHECK_FUNCS(strtoul bsearch putenv popen bcopy bzero bcmp \
 	index rindex strchr strrchr kill getrlimit setrlimit atoll atoq \
 	sysconf isascii gettimeofday strsignal putc_unlocked fputc_unlocked \
-	fputs_unlocked getrusage valloc)
+	fputs_unlocked getrusage)
 
 AC_CHECK_TYPE(ssize_t, int)
 
@@ -510,7 +510,6 @@
   ;;
 esac
 AC_FUNC_VFORK
-AC_FUNC_MMAP_ANYWHERE
 AC_FUNC_MMAP_FILE
 
 # We will need to find libiberty.h and ansidecl.h
@@ -4242,7 +4241,7 @@
 		symbolic_link="cp"
 	fi
 	cc_set_by_configure="\`case '\$(CC)' in stage*) echo '\$(CC)' | sed -e 's|stage|../stage|g';; *) echo '\$(CC)';; esac\`"
-	quoted_cc_set_by_configure="\\\`case '\\\$(CC)' in stage*) echo '\\\$(CC)' | sed -e 's|stage|../stage|g';; *) echo '\\\$(CC)';; esac\\\`"
+        quoted_cc_set_by_configure="\\\`case '\$(CC)' in stage*) echo '\$(CC)' | sed -e 's|stage|../stage|g';; *) echo '\$(CC)';; esac\\\`"
 	stage_prefix_set_by_configure="\`case '\$(STAGE_PREFIX)' in stage*) echo '\$(STAGE_PREFIX)' | sed -e 's|stage|../stage|g';; *) echo '\$(STAGE_PREFIX)';; esac\`"
 fi
 rm -f symtest.tem
@@ -4765,13 +4764,7 @@
   *)
     AC_MSG_ERROR([$withval is an invalid option to --with-gc])
     ;;
-esac],
-[if test $ac_cv_func_mmap_anywhere = yes \
-    || test $ac_cv_func_valloc = yes; then
-  GGC=ggc-page
-else
-  GGC=ggc-simple
-fi])
+esac], [GGC=ggc-page])
 AC_SUBST(GGC)
 echo "Using $GGC for garbage collection."
 
Index: gcc/ggc-page.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/ggc-page.c,v
retrieving revision 1.28
diff -u -r1.28 ggc-page.c
--- ggc-page.c	2000/07/23 16:25:06	1.28
+++ ggc-page.c	2000/07/28 07:25:47
@@ -29,18 +29,6 @@
 #include "ggc.h"
 #include "timevar.h"
 
-#ifdef HAVE_MMAP_ANYWHERE
-#include <sys/mman.h>
-#endif
-
-#ifndef MAP_FAILED
-#define MAP_FAILED -1
-#endif
-
-#if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-
 /* Stategy: 
 
    This garbage-collecting allocator allocates objects on one of a set
@@ -215,6 +203,10 @@
   size_t pagesize;
   size_t lg_pagesize;
 
+  /* The system's page size minus any overheads of the page allocation
+     system.  */
+  size_t usable_pagesize;
+
   /* Bytes currently allocated.  */
   size_t allocated;
 
@@ -227,11 +219,6 @@
   /* The current depth in the context stack.  */
   unsigned short context_depth;
 
-  /* A file descriptor open to /dev/zero for reading.  */
-#if defined (HAVE_MMAP_ANYWHERE) && !defined(MAP_ANONYMOUS)
-  int dev_zero_fd;
-#endif
-
   /* A cache of free system pages.  */
   page_entry *free_pages;
 
@@ -247,7 +234,8 @@
 /* The number of objects per allocation page, for objects of size
    2^ORDER.  */
 #define OBJECTS_PER_PAGE(Order) \
-  ((Order) >= G.lg_pagesize ? 1 : G.pagesize / ((size_t)1 << (Order)))
+  ((Order) >= G.lg_pagesize ? 1 \
+   : ((G.usable_pagesize) / ((size_t)1 << (Order))))
 
 /* The size in bytes required to maintain a bitmap for the objects
    on a page-entry.  */
@@ -264,11 +252,14 @@
    test from triggering too often when the heap is small.  */
 #define GGC_MIN_LAST_ALLOCATED (4 * 1024 * 1024)
 
+/* Test the misalignment of an address.  */
+#define MISALIGNMENT(Address) \
+  (((size_t)(Address)) & (G.pagesize - 1))
+
 
 static int ggc_allocated_p PARAMS ((const void *));
 static page_entry *lookup_page_table_entry PARAMS ((const void *));
 static void set_page_table_entry PARAMS ((void *, page_entry *));
-static char *alloc_anon PARAMS ((char *, size_t));
 static struct page_entry * alloc_page PARAMS ((unsigned));
 static void free_page PARAMS ((struct page_entry *));
 static void release_pages PARAMS ((void));
@@ -399,46 +390,6 @@
   fflush (stdout);
 }
 
-/* Allocate SIZE bytes of anonymous memory, preferably near PREF,
-   (if non-null).  */
-
-static inline char *
-alloc_anon (pref, size)
-     char *pref ATTRIBUTE_UNUSED;
-     size_t size;
-{
-  char *page;
-
-#ifdef HAVE_MMAP_ANYWHERE
-#ifdef MAP_ANONYMOUS
-  page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
-			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-#else
-  page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
-			MAP_PRIVATE, G.dev_zero_fd, 0);
-#endif
-  if (page == (char *) MAP_FAILED)
-    {
-      fputs ("Virtual memory exhausted!\n", stderr);
-      exit(1);
-    }
-#else
-#ifdef HAVE_VALLOC
-  page = (char *) valloc (size);
-  if (!page)
-    {
-      fputs ("Virtual memory exhausted!\n", stderr);
-      exit(1);
-    }
-#endif /* HAVE_VALLOC */
-#endif /* HAVE_MMAP_ANYWHERE */
-
-  /* Remember that we allocated this memory.  */
-  G.bytes_mapped += size;
-
-  return page;
-}
-
 /* Allocate a new page for allocating objects of size 2^ORDER,
    and return an entry for it.  The entry is not added to the
    appropriate page_table list.  */
@@ -484,7 +435,10 @@
   else
     {
       /* Actually allocate the memory.  */
-      page = alloc_anon (NULL, entry_size);
+      page = xvalloc (entry_size);
+
+      /* Remember that we actually allocated this memory.  */
+      G.bytes_mapped += entry_size;
     }
 
   if (entry == NULL)
@@ -534,54 +488,15 @@
 static void
 release_pages ()
 {
-#ifdef HAVE_MMAP_ANYWHERE
-  page_entry *p, *next;
-  char *start;
-  size_t len;
-
-  p = G.free_pages;
-  if (p == NULL)
-    return;
-
-  next = p->next;
-  start = p->page;
-  len = p->bytes;
-  free (p);
-  p = next;
-
-  while (p)
-    {
-      next = p->next;
-      /* Gather up adjacent pages so they are unmapped together.  */
-      if (p->page == start + len)
-	len += p->bytes;
-      else
-	{
-	  munmap (start, len);
-	  G.bytes_mapped -= len;
-	  start = p->page;
-	  len = p->bytes;
-	}
-      free (p);
-      p = next;
-    }
-
-  munmap (start, len);
-  G.bytes_mapped -= len;
-#else
-#ifdef HAVE_VALLOC
   page_entry *p, *next;
 
   for (p = G.free_pages; p ; p = next)
     {
       next = p->next;
-      free (p->page);
+      xvfree (p->page, p->bytes);
       G.bytes_mapped -= p->bytes;
       free (p);
     }
-#endif /* HAVE_VALLOC */
-#endif /* HAVE_MMAP_ANYWHERE */
-
   G.free_pages = NULL;
 }
 
@@ -783,7 +698,7 @@
   return 1 << pe->order;
 }
 
-/* Initialize the ggc-mmap allocator.  */
+/* Initialize the ggc-page allocator.  */
 
 void
 init_ggc ()
@@ -791,40 +706,16 @@
   G.pagesize = getpagesize();
   G.lg_pagesize = exact_log2 (G.pagesize);
 
-#if defined (HAVE_MMAP_ANYWHERE) && !defined(MAP_ANONYMOUS)
-  G.dev_zero_fd = open ("/dev/zero", O_RDONLY);
-  if (G.dev_zero_fd == -1)
-    abort ();
-#endif
+  G.usable_pagesize = G.pagesize - xvalloc_overhead();
 
 #if 0
-  G.debug_file = fopen ("ggc-mmap.debug", "w");
+  G.debug_file = fopen ("ggc-page.debug", "w");
 #else
   G.debug_file = stdout;
 #endif
 
   G.allocated_last_gc = GGC_MIN_LAST_ALLOCATED;
 
-#ifdef HAVE_MMAP_ANYWHERE
-  /* StunOS has an amazing off-by-one error for the first mmap allocation
-     after fiddling with RLIMIT_STACK.  The result, as hard as it is to
-     believe, is an unaligned page allocation, which would cause us to
-     hork badly if we tried to use it.  */
-  {
-    char *p = alloc_anon (NULL, G.pagesize);
-    if ((size_t)p & (G.pagesize - 1))
-      {
-	/* How losing.  Discard this one and try another.  If we still
-	   can't get something useful, give up.  */
-
-	p = alloc_anon (NULL, G.pagesize);
-	if ((size_t)p & (G.pagesize - 1))
-	  abort ();
-      }
-    munmap (p, G.pagesize);
-  }
-#endif
-
   empty_string = ggc_alloc_string ("", 0);
   ggc_add_string_root (&empty_string, 1);
 }
@@ -931,7 +822,7 @@
 	{
 #ifdef ENABLE_CHECKING
 	  /* The data should be page-aligned.  */
-	  if ((size_t) p->page & (G.pagesize - 1))
+	  if (MISALIGNMENT(p->page))
 	    abort ();
 #endif
 
Index: libiberty/Makefile.in
===================================================================
RCS file: /cvs/gcc/egcs/libiberty/Makefile.in,v
retrieving revision 1.52
diff -u -r1.52 Makefile.in
--- Makefile.in	2000/07/26 23:23:24	1.52
+++ Makefile.in	2000/07/28 07:27:01
@@ -135,7 +135,7 @@
 	strchr.c strdup.c strerror.c strncmp.c strrchr.c strsignal.c strstr.c \
 	strtod.c strtol.c strtoul.c tmpnam.c vasprintf.c vfork.c vfprintf.c   \
 	vprintf.c vsprintf.c waitpid.c xatexit.c xexit.c xmalloc.c	      \
-	xmemdup.c xstrdup.c xstrerror.c
+	xmemdup.c xstrdup.c xstrerror.c xvalloc.c
 
 # These are always included in the library.
 REQUIRED_OFILES = argv.o choose-temp.o concat.o cplus-dem.o cp-demangle.o \
@@ -143,7 +143,7 @@
 	getruntime.o hashtab.o hex.o floatformat.o objalloc.o obstack.o	  \
 	partition.o pexecute.o sort.o spaces.o splay-tree.o strerror.o	  \
 	strsignal.o xatexit.o xexit.o xmalloc.o xmemdup.o xstrdup.o	  \
-	xstrerror.o
+	xstrerror.o xvalloc.o
 
 $(TARGETLIB): $(REQUIRED_OFILES) $(EXTRA_OFILES) $(LIBOBJS) $(ALLOCA)
 	rm -f $(TARGETLIB)
@@ -296,5 +296,9 @@
 xmemdup.o: config.h $(INCDIR)/libiberty.h
 xstrdup.o: config.h $(INCDIR)/libiberty.h
 xstrerror.o: config.h $(INCDIR)/libiberty.h
+xvalloc.o: config.h $(INCDIR)/libiberty.h
 waitpid.o: config.h
 hashtab.o: config.h $(INCDIR)/libiberty.h $(INCDIR)/hashtab.h $(INCDIR)/ansidecl.h

Index: libiberty/configure.in
===================================================================
RCS file: /cvs/gcc/egcs/libiberty/configure.in,v
retrieving revision 1.28
diff -u -r1.28 configure.in
--- configure.in	2000/07/23 19:18:32	1.28
+++ configure.in	2000/07/28 07:27:18
@@ -357,6 +357,89 @@
 
 libiberty_AC_FUNC_STRNCMP
 
+AC_DEFUN([AC_FUNC_MMAP_ANYWHERE],
+[AC_CHECK_HEADERS(unistd.h)
+AC_CHECK_FUNCS(getpagesize)
+AC_CACHE_CHECK(for working mmap from /dev/zero, ac_cv_func_mmap_anywhere,
+[AC_TRY_RUN([
+/* Test by Richard Henderson and Alexandre Oliva.
+   Check whether mmap from /dev/zero works. */
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+/* This mess was copied from the GNU getpagesize.h.  */
+#ifndef HAVE_GETPAGESIZE
+# ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+# endif
+
+/* Assume that all systems that can run configure have sys/param.h.  */
+# ifndef HAVE_SYS_PARAM_H
+#  define HAVE_SYS_PARAM_H 1
+# endif
+
+# ifdef _SC_PAGESIZE
+#  define getpagesize() sysconf(_SC_PAGESIZE)
+# else /* no _SC_PAGESIZE */
+#  ifdef HAVE_SYS_PARAM_H
+#   include <sys/param.h>
+#   ifdef EXEC_PAGESIZE
+#    define getpagesize() EXEC_PAGESIZE
+#   else /* no EXEC_PAGESIZE */
+#    ifdef NBPG
+#     define getpagesize() NBPG * CLSIZE
+#     ifndef CLSIZE
+#      define CLSIZE 1
+#     endif /* no CLSIZE */
+#    else /* no NBPG */
+#     ifdef NBPC
+#      define getpagesize() NBPC
+#     else /* no NBPC */
+#      ifdef PAGESIZE
+#       define getpagesize() PAGESIZE
+#      endif /* PAGESIZE */
+#     endif /* no NBPC */
+#    endif /* no NBPG */
+#   endif /* no EXEC_PAGESIZE */
+#  else /* no HAVE_SYS_PARAM_H */
+#   define getpagesize() 8192  /* punt totally */
+#  endif /* no HAVE_SYS_PARAM_H */
+# endif /* no _SC_PAGESIZE */
+
+#endif /* no HAVE_GETPAGESIZE */
+
+int main()
+{
+  char *x;
+  int fd, pg;
+
+  fd = open("/dev/zero", O_RDWR);
+  if (fd < 0)
+    exit(1);
+
+  pg = getpagesize();
+  x = (char*)mmap(0, pg, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
+  if (x == (char *) -1)
+    exit(2);
+
+  *(int *)x += 1;
+
+  if (munmap(x, pg) < 0)
+    exit(3);
+
+  exit(0);
+}], ac_cv_func_mmap_anywhere=yes, ac_cv_func_mmap_anywhere=no,
+ac_cv_func_mmap_anywhere=no)])
+if test $ac_cv_func_mmap_anywhere = yes; then
+  AC_DEFINE(HAVE_MMAP_ANYWHERE, 1,
+           [Define if mmap can get us zeroed pages from /dev/zero.])
+fi
+])
+
+AC_FUNC_MMAP_ANYWHERE
+AC_CHECK_FUNCS(valloc)
+
 # Install a library built with a cross compiler in $(tooldir) rather
 # than $(libdir).
 if test -z "${with_cross_host}"; then

Index: libiberty/xvalloc.c
===================================================================
RCS file: xvalloc.c
diff -N xvalloc.c
--- /dev/null	Fri Jul 28 10:22:03 2000
+++ xvalloc.c	Fri Jul 28 09:59:40 2000
@@ -0,0 +1,286 @@
+/* page-aligned memory allocation routines.
+   Copyright (C) 1999, 2000 Free Software Foundation
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB.  If not, write
+to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libiberty.h>
+
+/* If defined to a positive number and malloc-based page allocation is
+   being used, counters are maintained for each successful allocation
+   using the mechanism that tries to convince malloc to return a
+   page-aligned address (aligned) and the fallback mechanism
+   (fallback).  Their values are printed every MALLOC_ACCOUNT
+   allocations. */
+#if 0
+# define MALLOC_ACCOUNT 16
+#endif
+
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+#if HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED -1
+#endif
+
+#if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/* The system's page size.  */
+static size_t pagesize;
+
+#if defined (MAP_ANONYMOUS) || HAVE_MMAP_ANYWHERE
+
+# define offset 0
+# define overhead 0
+
+# ifndef MAP_ANONYMOUS
+static int dev_zero_fd;
+# endif
+
+#else
+
+#if HAVE_VALLOC
+static int use_valloc;
+#else
+# define use_valloc 0
+#endif
+
+/* This is usually 0, but AIX 4.1.5's malloc, for example, always
+   returns addresses p=16n+8.  This variable is supposed to be used as
+   an offset from the value returned by malloc to the beginning of the
+   page. */
+static size_t offset;
+
+/* This is how much space is used up by malloc internal structures.
+   It's typically 8 or 16 bytes. */
+static size_t overhead;
+#endif
+
+/* Test the misalignment of an address.  */
+#define MISALIGNMENT(Address) \
+  (((size_t)(Address)) & (pagesize - 1))
+
+#if ! defined (MAP_ANONYMOUS) && ! HAVE_MMAP_ANYWHERE
+static void
+xvmalloc_set_pointer (page, other)
+     char *page, *other;
+{
+  /* Set the pointer just before the page boundary to the beginning of
+     the block, so that it can be freed afterwards. */
+  ((char**)page)[-1] = other;
+}
+
+static char *
+xvmalloc_get_pointer (page)
+     char *page;
+{
+   return ((char**)page)[-1];
+}
+
+/* Return a page-aligned memory block with as many bytes as requested
+   in the page. */
+static char *
+xvmalloc_fallback (size)
+     size_t size;
+{
+  char *page, *other;
+
+  other = xmalloc(size + pagesize + offset - 1);
+  page = (char *)((size_t)(other + pagesize) & ~(pagesize - 1));
+
+  /* Mark its beginning. */
+  xvmalloc_set_pointer (page, other);
+
+  return page;
+}
+#endif /* ! defined (MAP_ANONYMOUS) && ! HAVE_MMAP_ANYWHERE */
+
+/* Return the number of bytes that should be subtracted from the
+   pagesize in order to avoid wasting every other page. */
+unsigned
+xvalloc_overhead ()
+{
+  if (pagesize)
+    return overhead + offset;
+
+  pagesize = getpagesize();
+
+#if ! defined (MAP_ANONYMOUS) && HAVE_MMAP_ANYWHERE
+  dev_zero_fd = open ("/dev/zero", O_RDONLY);
+  if (dev_zero_fd == -1)
+    abort ();
+#endif
+
+#if defined (MAP_ANONYMOUS) || HAVE_MMAP_ANYWHERE
+  /* StunOS has an amazing off-by-one error for the first mmap allocation
+     after fiddling with RLIMIT_STACK.  The result, as hard as it is to
+     believe, is an unaligned page allocation, which would cause us to
+     hork badly if we tried to use it.  */
+  {
+    char *p = xvalloc (pagesize);
+    if (MISALIGNMENT (p))
+      {
+       /* How losing.  Discard this one and try another.  If we still
+          can't get something useful, give up.  */
+
+       p = xvalloc (pagesize);
+       if (MISALIGNMENT (p))
+         abort ();
+      }
+    xvfree (p, pagesize);
+  }
+#else
+# if HAVE_VALLOC
+  {
+    char *to_free = 0, *p = 0, *q = 0;
+
+    /* If valloc imposes some space overhead, try to leave some bytes
+       at the end of the page, so as not to waste every other page. */
+    for (overhead = 0; overhead < pagesize;
+        overhead = overhead ? 2 * overhead : sizeof (char*))
+      {
+       p = valloc (pagesize - overhead);
+       if (! p)
+         {
+           overhead = pagesize;
+           break;
+         }
+       *(char**)p = to_free;
+
+       q = valloc (pagesize - overhead);
+       if (! q)
+         {
+           overhead = pagesize;
+           break;
+         }
+       *(char**)q = p;
+
+       to_free = q;
+       if (q - p <= pagesize)
+         break;
+      }
+
+    /* Set use_valloc so that xvfree() uses the appropriate free
+       mechanism. */
+    use_valloc = 1;
+    while (to_free)
+      {
+       p = to_free;
+       to_free = *(char**)p;
+
+       /* Note: the second argument is unused when the allocation
+          mechanism is xvalloc. */
+       xvfree (p, 0);
+      }
+
+    /* We'll only use valloc if we can arrange to not waste pages. */
+    use_valloc = (overhead < pagesize);
+  }
+# endif
+  /* If we're not using valloc, let's configure with plain malloc. */
+  overhead = offset = 0;
+#endif /* defined (MAP_ANONYMOUS) || HAVE_MMAP_ANYWHERE */
+
+  return overhead + offset;
+}
+
+/* Return a page-aligned block of memory of length size. */
+char*
+xvalloc(size)
+     size_t size;
+{
+  char *page;
+
+#if HAVE_MMAP_ANYWHERE || defined (MAP_ANONYMOUS)
+# ifdef MAP_ANONYMOUS
+  page = (char *) mmap (0, size, PROT_READ | PROT_WRITE,
+                       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+# else
+  page = (char *) mmap (0, size, PROT_READ | PROT_WRITE,
+                       MAP_PRIVATE, dev_zero_fd, 0);
+# endif
+  if (page == (char *) MAP_FAILED)
+    {
+      fputs ("Virtual memory exhausted!\n", stderr);
+      exit(1);
+    }
+#else
+
+# if HAVE_VALLOC
+  if (use_valloc)
+    {
+      page = (char *) valloc (size);
+      if (!page)
+       {
+         fputs ("Virtual memory exhausted!\n", stderr);
+         exit(1);
+       }
+    }
+# endif
+
+  if (! use_valloc)
+      page = xvmalloc_fallback (size);
+
+#endif /* defined (MAP_ANONYMOUS) || HAVE_MMAP_ANYWHERE */
+
+  return page;
+}
+
+/* Releases the memory block that has previously been returned by
+   xvalloc(size). */
+void
+xvfree(page, size)
+     char *page;
+     size_t size;
+{
+#if defined (MAP_ANONYMOUS) || HAVE_MMAP_ANYWHERE
+  munmap (page, size);
+#else
+# if HAVE_VALLOC
+  /* The docs say we shouldn't be using free() for valloc().  However,
+     no configure test that would fail for such use could be
+     implemented; it just worked.  If a failure situation is ever
+     found, a configure test that AC_DEFINEs HAVE_VALLOC to 0 should
+     be added. */
+  if (use_valloc)
+    free (page);
+# endif
+  if (! use_valloc)
+    free (xvmalloc_get_pointer (page));
+#endif
+}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019