]>
Commit | Line | Data |
---|---|---|
c906108c | 1 | /* Support for an sbrk-like function that uses mmap. |
9365c12c | 2 | Copyright 1992, 2000 Free Software Foundation, Inc. |
c906108c SS |
3 | |
4 | Contributed by Fred Fish at Cygnus Support. [email protected] | |
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 | ||
9365c12c AC |
25 | #ifdef HAVE_UNISTD_H |
26 | #include <unistd.h> /* Prototypes for lseek */ | |
27 | #endif | |
c906108c SS |
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; | |
ff4e7bb2 | 44 | #if NEED_DECLARATION_GETPAGESIZE |
c906108c | 45 | extern int getpagesize PARAMS ((void)); |
ff4e7bb2 | 46 | #endif |
c906108c SS |
47 | |
48 | #define PAGE_ALIGN(addr) (caddr_t) (((long)(addr) + pagesize - 1) & \ | |
49 | ~(pagesize - 1)) | |
50 | ||
aeec20ba AC |
51 | |
52 | /* Return MAP_PRIVATE if MDP represents /dev/zero. Otherwise, return | |
53 | MAP_SHARED. */ | |
54 | ||
55 | #define MAP_PRIVATE_OR_SHARED(MDP) ((MDP -> flags & MMALLOC_DEVZERO) \ | |
56 | ? MAP_PRIVATE \ | |
57 | : MAP_SHARED) | |
58 | ||
59 | ||
c906108c SS |
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 | PTR | |
65 | __mmalloc_mmap_morecore (mdp, size) | |
66 | struct mdesc *mdp; | |
67 | int size; | |
68 | { | |
69 | PTR result = NULL; | |
70 | off_t foffset; /* File offset at which new mapping will start */ | |
71 | size_t mapbytes; /* Number of bytes to map */ | |
72 | caddr_t moveto; /* Address where we wish to move "break value" to */ | |
73 | caddr_t mapto; /* Address we actually mapped to */ | |
74 | char buf = 0; /* Single byte to write to extend mapped file */ | |
75 | ||
76 | if (pagesize == 0) | |
77 | { | |
78 | pagesize = getpagesize (); | |
79 | } | |
80 | if (size == 0) | |
81 | { | |
82 | /* Just return the current "break" value. */ | |
83 | result = mdp -> breakval; | |
84 | } | |
85 | else if (size < 0) | |
86 | { | |
87 | /* We are deallocating memory. If the amount requested would cause | |
88 | us to try to deallocate back past the base of the mmap'd region | |
89 | then do nothing, and return NULL. Otherwise, deallocate the | |
90 | memory and return the old break value. */ | |
91 | if (mdp -> breakval + size >= mdp -> base) | |
92 | { | |
93 | result = (PTR) mdp -> breakval; | |
94 | mdp -> breakval += size; | |
95 | moveto = PAGE_ALIGN (mdp -> breakval); | |
96 | munmap (moveto, (size_t) (mdp -> top - moveto)); | |
97 | mdp -> top = moveto; | |
98 | } | |
99 | } | |
100 | else | |
101 | { | |
102 | /* We are allocating memory. Make sure we have an open file | |
103 | descriptor and then go on to get the memory. */ | |
104 | if (mdp -> fd < 0) | |
105 | { | |
106 | result = NULL; | |
107 | } | |
108 | else if (mdp -> breakval + size > mdp -> top) | |
109 | { | |
110 | /* The request would move us past the end of the currently | |
111 | mapped memory, so map in enough more memory to satisfy | |
112 | the request. This means we also have to grow the mapped-to | |
113 | file by an appropriate amount, since mmap cannot be used | |
114 | to extend a file. */ | |
115 | moveto = PAGE_ALIGN (mdp -> breakval + size); | |
116 | mapbytes = moveto - mdp -> top; | |
117 | foffset = mdp -> top - mdp -> base; | |
118 | /* FIXME: Test results of lseek() and write() */ | |
119 | lseek (mdp -> fd, foffset + mapbytes - 1, SEEK_SET); | |
120 | write (mdp -> fd, &buf, 1); | |
121 | if (mdp -> base == 0) | |
122 | { | |
123 | /* Let mmap pick the map start address */ | |
124 | mapto = mmap (0, mapbytes, PROT_READ | PROT_WRITE, | |
aeec20ba | 125 | MAP_PRIVATE_OR_SHARED (mdp), mdp -> fd, foffset); |
c906108c SS |
126 | if (mapto != (caddr_t) -1) |
127 | { | |
128 | mdp -> base = mdp -> breakval = mapto; | |
129 | mdp -> top = mdp -> base + mapbytes; | |
130 | result = (PTR) mdp -> breakval; | |
131 | mdp -> breakval += size; | |
132 | } | |
133 | } | |
134 | else | |
135 | { | |
136 | mapto = mmap (mdp -> top, mapbytes, PROT_READ | PROT_WRITE, | |
aeec20ba AC |
137 | MAP_PRIVATE_OR_SHARED (mdp) | MAP_FIXED, mdp -> fd, |
138 | foffset); | |
c906108c SS |
139 | if (mapto == mdp -> top) |
140 | { | |
141 | mdp -> top = moveto; | |
142 | result = (PTR) mdp -> breakval; | |
143 | mdp -> breakval += size; | |
144 | } | |
145 | } | |
146 | } | |
147 | else | |
148 | { | |
149 | result = (PTR) mdp -> breakval; | |
150 | mdp -> breakval += size; | |
151 | } | |
152 | } | |
153 | return (result); | |
154 | } | |
155 | ||
156 | PTR | |
157 | __mmalloc_remap_core (mdp) | |
158 | struct mdesc *mdp; | |
159 | { | |
160 | caddr_t base; | |
161 | ||
162 | /* FIXME: Quick hack, needs error checking and other attention. */ | |
163 | ||
164 | base = mmap (mdp -> base, mdp -> top - mdp -> base, | |
aeec20ba | 165 | PROT_READ | PROT_WRITE, MAP_PRIVATE_OR_SHARED (mdp) | MAP_FIXED, |
c906108c SS |
166 | mdp -> fd, 0); |
167 | return ((PTR) base); | |
168 | } | |
169 | ||
170 | PTR | |
171 | mmalloc_findbase (size) | |
172 | int size; | |
173 | { | |
174 | int fd; | |
175 | int flags; | |
176 | caddr_t base = NULL; | |
177 | ||
178 | #ifdef MAP_ANONYMOUS | |
aeec20ba | 179 | flags = MAP_PRIVATE | MAP_ANONYMOUS; |
c906108c SS |
180 | fd = -1; |
181 | #else | |
182 | #ifdef MAP_FILE | |
aeec20ba | 183 | flags = MAP_PRIVATE | MAP_FILE; |
c906108c | 184 | #else |
aeec20ba | 185 | flags = MAP_PRIVATE; |
c906108c SS |
186 | #endif |
187 | fd = open ("/dev/zero", O_RDWR); | |
188 | if (fd != -1) | |
189 | { | |
190 | return ((PTR) NULL); | |
191 | } | |
192 | #endif | |
193 | base = mmap (0, size, PROT_READ | PROT_WRITE, flags, fd, 0); | |
194 | if (base != (caddr_t) -1) | |
195 | { | |
196 | munmap (base, (size_t) size); | |
197 | } | |
198 | if (fd != -1) | |
199 | { | |
200 | close (fd); | |
201 | } | |
202 | if (base == 0) | |
203 | { | |
204 | /* Don't allow mapping at address zero. We use that value | |
205 | to signal an error return, and besides, it is useful to | |
206 | catch NULL pointers if it is unmapped. Instead start | |
207 | at the next page boundary. */ | |
208 | base = (caddr_t) getpagesize (); | |
209 | } | |
210 | else if (base == (caddr_t) -1) | |
211 | { | |
212 | base = NULL; | |
213 | } | |
214 | return ((PTR) base); | |
215 | } | |
216 | ||
217 | #else /* defined(HAVE_MMAP) */ | |
218 | /* Prevent "empty translation unit" warnings from the idiots at X3J11. */ | |
219 | static char ansi_c_idiots = 69; | |
220 | #endif /* defined(HAVE_MMAP) */ |