Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Now supernovae mode works out of project directory.
[simgrid.git] / src / xbt / mmalloc / mmap-sup.c
1 /* Support for an sbrk-like function that uses mmap.
2    Copyright 1992, 2000 Free Software Foundation, Inc.
3
4    Contributed by Fred Fish at Cygnus Support.   fnf@cygnus.com */
5
6 /* Copyright (c) 2010. The SimGrid Team.
7  * All rights reserved.                                                     */
8
9 /* This program is free software; you can redistribute it and/or modify it
10  * under the terms of the license (GNU LGPL) which comes with this package. */
11
12 #ifndef MAP_ANONYMOUS
13         #define MAP_ANONYMOUS MAP_ANON
14 #endif
15
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>     /* Prototypes for lseek */
18 #endif
19 #include <stdio.h>
20 #include <fcntl.h>
21 #include <sys/mman.h>
22
23 #ifndef SEEK_SET
24 #define SEEK_SET 0
25 #endif
26
27 #include "mmprivate.h"
28
29 /* Cache the pagesize for the current host machine.  Note that if the host
30    does not readily provide a getpagesize() function, we need to emulate it
31    elsewhere, not clutter up this file with lots of kluges to try to figure
32    it out. */
33
34 static size_t pagesize;
35 #if NEED_DECLARATION_GETPAGESIZE
36 extern int getpagesize (void);
37 #endif
38
39 #define PAGE_ALIGN(addr) (void*) (((long)(addr) + pagesize - 1) & \
40                                     ~(pagesize - 1))
41
42 /* Return MAP_PRIVATE if MDP represents /dev/zero.  Otherwise, return
43    MAP_SHARED.  */
44
45 #define MAP_PRIVATE_OR_SHARED(MDP) (( MDP -> flags & MMALLOC_ANONYMOUS) \
46                                     ? MAP_PRIVATE \
47                                     : MAP_SHARED)
48
49 /* Return MAP_ANONYMOUS if MDP uses anonymous mapping. Otherwise, return 0 */
50
51 #define MAP_IS_ANONYMOUS(MDP) (((MDP) -> flags & MMALLOC_ANONYMOUS) \
52                               ? MAP_ANONYMOUS \
53                               : 0)
54
55 /* Return -1 if MDP uses anonymous mapping. Otherwise, return MDP->FD */
56 #define MAP_ANON_OR_FD(MDP) (((MDP) -> flags & MMALLOC_ANONYMOUS) \
57                               ? -1 \
58                                               : (MDP) -> fd)
59
60 /*  Get core for the memory region specified by MDP, using SIZE as the
61     amount to either add to or subtract from the existing region.  Works
62     like sbrk(), but using mmap(). */
63
64 void*
65 __mmalloc_mmap_morecore (struct mdesc *mdp, int size)
66 {
67   ssize_t test = 0;
68   void* result = NULL;
69   off_t foffset;        /* File offset at which new mapping will start */
70   size_t mapbytes;      /* Number of bytes to map */
71   void* moveto; /* Address where we wish to move "break value" to */
72   void* mapto;  /* Address we actually mapped to */
73   char buf = 0;         /* Single byte to write to extend mapped file */
74
75   if (pagesize == 0)
76     pagesize = getpagesize();
77
78   if (size == 0)
79   {
80     /* Just return the current "break" value. */
81     result = mdp -> breakval;
82   }
83   else if (size < 0)
84   {
85     /* We are deallocating memory.  If the amount requested would cause
86              us to try to deallocate back past the base of the mmap'd region
87              then do nothing, and return NULL.  Otherwise, deallocate the
88              memory and return the old break value. */
89     if (((char*)mdp -> breakval) + size >= (char*)mdp -> base)
90           {
91             result = (void*) mdp -> breakval;
92             mdp -> breakval = (char*) mdp->breakval + size;
93             moveto = PAGE_ALIGN (mdp -> breakval);
94             munmap (moveto, (size_t) (((char*)mdp -> top) - ((char*)moveto)) - 1);
95             mdp -> top = moveto;
96           }
97   }
98   else
99   {
100     /* We are allocating memory. Make sure we have an open file
101              descriptor if not working with anonymous memory. */
102     if ( !(mdp->flags & MMALLOC_ANONYMOUS) && mdp -> fd < 0)
103           {
104             result = NULL;
105           }
106     else if ((char*)mdp -> breakval + size > (char*)mdp -> top)
107           {
108           /* The request would move us past the end of the currently
109              mapped memory, so map in enough more memory to satisfy
110              the request.  This means we also have to grow the mapped-to
111              file by an appropriate amount, since mmap cannot be used
112              to extend a file. */
113             moveto = PAGE_ALIGN ((char*)mdp -> breakval + size);
114             mapbytes = (char*)moveto - (char*)mdp -> top;
115             foffset = (char*)mdp -> top - (char*)mdp -> base;
116
117       if( mdp -> fd > 0){
118           /* FIXME:  Test results of lseek() and write() */
119         lseek (mdp -> fd, foffset + mapbytes - 1, SEEK_SET);
120         test = write (mdp -> fd, &buf, 1);
121       }
122             
123             /* Let's call mmap. Note that it is possible that mdp->top
124                is 0. In this case mmap will choose the address for us */
125       mapto = mmap (mdp->top, mapbytes, PROT_READ | PROT_WRITE,
126         MAP_PRIVATE_OR_SHARED(mdp) | MAP_IS_ANONYMOUS(mdp) | MAP_FIXED,
127         MAP_ANON_OR_FD(mdp), foffset);
128
129       if (mapto != (void*) -1){
130             
131         if(mdp -> top == 0)
132           mdp -> base = mdp -> breakval = mapto;
133         
134         mdp -> top = PAGE_ALIGN ((char*)mdp -> breakval + size);
135         result = (void*) mdp -> breakval;
136         mdp -> breakval = (char*)mdp->breakval + size;
137       }
138           }
139     else
140           {
141             result = (void*) mdp -> breakval;
142             mdp -> breakval = (char*)mdp->breakval + size;
143           }
144   }
145   return (result);
146 }
147
148 void*
149 __mmalloc_remap_core (struct mdesc *mdp)
150 {
151   void* base;
152
153   /* FIXME:  Quick hack, needs error checking and other attention. */
154
155   base = mmap (mdp -> base, (char*)mdp -> top - (char*)mdp -> base,
156                PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE_OR_SHARED (mdp) | MAP_FIXED,
157                mdp -> fd, 0);
158   return ((void*) base);
159 }
160
161 void*
162 mmalloc_findbase (int size)
163 {
164   int fd;
165   int flags;
166   void* base = NULL;
167
168 #ifdef MAP_ANONYMOUS
169   flags = MAP_PRIVATE | MAP_ANONYMOUS;
170   fd = -1;
171 #else
172 #ifdef MAP_FILE
173   flags = MAP_PRIVATE | MAP_FILE;
174 #else
175   flags = MAP_PRIVATE;
176 #endif
177   fd = open ("/dev/zero", O_RDWR);
178   if (fd != -1)
179     {
180       return ((void*) NULL);
181     }
182 #endif
183   base = mmap (0, size, PROT_READ | PROT_WRITE, flags, fd, 0);
184   if (base != (void*) -1)
185     {
186       munmap (base, (size_t) size);
187     }
188   if (fd != -1)
189     {
190       close (fd);
191     }
192   if (base == 0)
193     {
194       /* Don't allow mapping at address zero.  We use that value
195          to signal an error return, and besides, it is useful to
196          catch NULL pointers if it is unmapped.  Instead start
197          at the next page boundary. */
198       base = (void*)(long) getpagesize ();
199     }
200   else if (base == (void*) -1)
201     {
202       base = NULL;
203     }
204   return ((void*) base);
205 }