Logo AND Algorithmique Numérique Distribuée

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