Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
New module: mmalloc (mapped malloc)
[simgrid.git] / src / xbt / mmalloc / mmap-sup.c
diff --git a/src/xbt/mmalloc/mmap-sup.c b/src/xbt/mmalloc/mmap-sup.c
new file mode 100644 (file)
index 0000000..ccaf7bb
--- /dev/null
@@ -0,0 +1,222 @@
+/* Support for an sbrk-like function that uses mmap.
+   Copyright 1992, 2000 Free Software Foundation, Inc.
+
+   Contributed by Fred Fish at Cygnus Support.   fnf@cygnus.com
+
+This file is part of the GNU C Library.
+
+The GNU C Library 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.
+
+The GNU C Library 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 the GNU C Library; 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 defined(HAVE_MMAP)
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>    /* Prototypes for lseek */
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#include "mmprivate.h"
+
+/* Cache the pagesize for the current host machine.  Note that if the host
+   does not readily provide a getpagesize() function, we need to emulate it
+   elsewhere, not clutter up this file with lots of kluges to try to figure
+   it out. */
+
+static size_t pagesize;
+#if NEED_DECLARATION_GETPAGESIZE
+extern int getpagesize PARAMS ((void));
+#endif
+
+#define PAGE_ALIGN(addr) (PTR) (((long)(addr) + pagesize - 1) & \
+                                   ~(pagesize - 1))
+
+/* Return MAP_PRIVATE if MDP represents /dev/zero.  Otherwise, return
+   MAP_SHARED.  */
+
+#define MAP_PRIVATE_OR_SHARED(MDP) ((MDP -> flags & MMALLOC_DEVZERO) \
+                                    ? MAP_PRIVATE \
+                                    : MAP_SHARED)
+
+/* Return MAP_ANONYMOUS if MDP uses anonymous mapping. Otherwise, return 0 */
+
+#define MAP_IS_ANONYMOUS(MDP) (((MDP) -> flags & MMALLOC_ANONYMOUS) \
+                              ? MAP_ANONYMOUS \
+                              : 0)
+
+/* Return -1 if MDP uses anonymous mapping. Otherwise, return MDP->FD */
+#define MAP_ANON_OR_FD(MDP) (((MDP) -> flags & MMALLOC_ANONYMOUS) \
+                              ? -1 \
+                                             : (MDP) -> fd)
+
+/*  Get core for the memory region specified by MDP, using SIZE as the
+    amount to either add to or subtract from the existing region.  Works
+    like sbrk(), but using mmap(). */
+
+PTR
+__mmalloc_mmap_morecore (mdp, size)
+  struct mdesc *mdp;
+  int size;
+{
+  PTR result = NULL;
+  off_t foffset;       /* File offset at which new mapping will start */
+  size_t mapbytes;     /* Number of bytes to map */
+  PTR moveto;  /* Address where we wish to move "break value" to */
+  PTR mapto;   /* Address we actually mapped to */
+  char buf = 0;                /* Single byte to write to extend mapped file */
+
+  if (pagesize == 0)
+    pagesize = getpagesize();
+
+  if (size == 0)
+  {
+    /* Just return the current "break" value. */
+    result = mdp -> breakval;
+  }
+  else if (size < 0)
+  {
+    /* We are deallocating memory.  If the amount requested would cause
+            us to try to deallocate back past the base of the mmap'd region
+            then do nothing, and return NULL.  Otherwise, deallocate the
+            memory and return the old break value. */
+    if (mdp -> breakval + size >= mdp -> base)
+         {
+           result = (PTR) mdp -> breakval;
+           mdp -> breakval += size;
+           moveto = PAGE_ALIGN (mdp -> breakval);
+           munmap (moveto, (size_t) (mdp -> top - moveto) - 1);
+           mdp -> top = moveto;
+         }
+  }
+  else
+  {
+    /* We are allocating memory. Make sure we have an open file
+            descriptor if not working with anonymous memory. */
+    if ( !(mdp->flags & MMALLOC_ANONYMOUS) && mdp -> fd < 0)
+         {
+           result = NULL;
+         }
+    else if (mdp -> breakval + size > mdp -> top)
+         {
+         /* The request would move us past the end of the currently
+            mapped memory, so map in enough more memory to satisfy
+            the request.  This means we also have to grow the mapped-to
+            file by an appropriate amount, since mmap cannot be used
+            to extend a file. */
+           moveto = PAGE_ALIGN (mdp -> breakval + size);
+           mapbytes = moveto - mdp -> top;
+           foffset = mdp -> top - mdp -> base;
+
+      if( mdp -> fd > 0){
+         /* FIXME:  Test results of lseek() and write() */
+        lseek (mdp -> fd, foffset + mapbytes - 1, SEEK_SET);
+             write (mdp -> fd, &buf, 1);
+      }
+           
+           /* Let's call mmap. Note that it is possible that mdp->top
+              is 0. In this case mmap will choose the address for us */
+      mapto = mmap (mdp->top, mapbytes, PROT_READ | PROT_WRITE,
+        MAP_PRIVATE_OR_SHARED(mdp) | MAP_IS_ANONYMOUS(mdp) | MAP_FIXED,
+        MAP_ANON_OR_FD(mdp), foffset);
+
+      if (mapto != (PTR) -1){
+           
+        if(mdp -> top == 0)
+          mdp -> base = mdp -> breakval = mapto;
+        
+        mdp -> top = PAGE_ALIGN (mdp -> breakval + size);
+        result = (PTR) mdp -> breakval;
+        mdp -> breakval += size;
+      }
+         }
+    else
+         {
+           result = (PTR) mdp -> breakval;
+           mdp -> breakval += size;
+         }
+  }
+  return (result);
+}
+
+PTR
+__mmalloc_remap_core (mdp)
+  struct mdesc *mdp;
+{
+  PTR base;
+
+  /* FIXME:  Quick hack, needs error checking and other attention. */
+
+  base = mmap (mdp -> base, mdp -> top - mdp -> base,
+              PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE_OR_SHARED (mdp) | MAP_FIXED,
+              mdp -> fd, 0);
+  return ((PTR) base);
+}
+
+PTR
+mmalloc_findbase (size)
+  int size;
+{
+  int fd;
+  int flags;
+  PTR base = NULL;
+
+#ifdef MAP_ANONYMOUS
+  flags = MAP_PRIVATE | MAP_ANONYMOUS;
+  fd = -1;
+#else
+#ifdef MAP_FILE
+  flags = MAP_PRIVATE | MAP_FILE;
+#else
+  flags = MAP_PRIVATE;
+#endif
+  fd = open ("/dev/zero", O_RDWR);
+  if (fd != -1)
+    {
+      return ((PTR) NULL);
+    }
+#endif
+  base = mmap (0, size, PROT_READ | PROT_WRITE, flags, fd, 0);
+  if (base != (PTR) -1)
+    {
+      munmap (base, (size_t) size);
+    }
+  if (fd != -1)
+    {
+      close (fd);
+    }
+  if (base == 0)
+    {
+      /* Don't allow mapping at address zero.  We use that value
+        to signal an error return, and besides, it is useful to
+        catch NULL pointers if it is unmapped.  Instead start
+        at the next page boundary. */
+      base = (PTR) getpagesize ();
+    }
+  else if (base == (PTR) -1)
+    {
+      base = NULL;
+    }
+  return ((PTR) base);
+}
+
+#else  /* defined(HAVE_MMAP) */
+/* Prevent "empty translation unit" warnings from the idiots at X3J11. */
+static char ansi_c_idiots = 69;
+#endif /* defined(HAVE_MMAP) */