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