Logo AND Algorithmique Numérique Distribuée

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