source: webkit/trunk/JavaScriptCore/wtf/TCSystemAlloc.cpp@ 21064

Last change on this file since 21064 was 20230, checked in by mjs, 18 years ago

Not reviewed.


  • build fix
  • wtf/TCSystemAlloc.cpp:
  • Property svn:eol-style set to native
File size: 10.5 KB
Line 
1// Copyright (c) 2005, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// ---
31// Author: Sanjay Ghemawat
32
33#include "config.h"
34#if HAVE(STDINT_H)
35#include <stdint.h>
36#elif HAVE(INTTYPES_H)
37#include <inttypes.h>
38#else
39#include <sys/types.h>
40#endif
41#if PLATFORM(WIN_OS)
42#include "windows.h"
43#else
44#include <unistd.h>
45#include <sys/mman.h>
46#endif
47#include <fcntl.h>
48#include "TCSystemAlloc.h"
49#include "TCSpinLock.h"
50
51#ifndef MAP_ANONYMOUS
52#define MAP_ANONYMOUS MAP_ANON
53#endif
54
55// Structure for discovering alignment
56union MemoryAligner {
57 void* p;
58 double d;
59 size_t s;
60};
61
62static SpinLock spinlock = SPINLOCK_INITIALIZER;
63
64// Page size is initialized on demand
65static size_t pagesize = 0;
66
67// Configuration parameters.
68//
69// if use_devmem is true, either use_sbrk or use_mmap must also be true.
70// For 2.2 kernels, it looks like the sbrk address space (500MBish) and
71// the mmap address space (1300MBish) are disjoint, so we need both allocators
72// to get as much virtual memory as possible.
73#ifndef WTF_CHANGES
74static bool use_devmem = false;
75#endif
76static bool use_sbrk = false;
77static bool use_mmap = true;
78#if HAVE(VIRTUALALLOC)
79static bool use_VirtualAlloc = true;
80#endif
81
82// Flags to keep us from retrying allocators that failed.
83static bool devmem_failure = false;
84static bool sbrk_failure = false;
85static bool mmap_failure = false;
86static bool VirtualAlloc_failure = false;
87
88#ifndef WTF_CHANGES
89DEFINE_int32(malloc_devmem_start, 0,
90 "Physical memory starting location in MB for /dev/mem allocation."
91 " Setting this to 0 disables /dev/mem allocation");
92DEFINE_int32(malloc_devmem_limit, 0,
93 "Physical memory limit location in MB for /dev/mem allocation."
94 " Setting this to 0 means no limit.");
95#else
96static const int32_t FLAGS_malloc_devmem_start = 0;
97static const int32_t FLAGS_malloc_devmem_limit = 0;
98#endif
99
100#if HAVE(SBRK)
101
102static void* TrySbrk(size_t size, size_t alignment) {
103 size = ((size + alignment - 1) / alignment) * alignment;
104 void* result = sbrk(size);
105 if (result == reinterpret_cast<void*>(-1)) {
106 sbrk_failure = true;
107 return NULL;
108 }
109
110 // Is it aligned?
111 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
112 if ((ptr & (alignment-1)) == 0) return result;
113
114 // Try to get more memory for alignment
115 size_t extra = alignment - (ptr & (alignment-1));
116 void* r2 = sbrk(extra);
117 if (reinterpret_cast<uintptr_t>(r2) == (ptr + size)) {
118 // Contiguous with previous result
119 return reinterpret_cast<void*>(ptr + extra);
120 }
121
122 // Give up and ask for "size + alignment - 1" bytes so
123 // that we can find an aligned region within it.
124 result = sbrk(size + alignment - 1);
125 if (result == reinterpret_cast<void*>(-1)) {
126 sbrk_failure = true;
127 return NULL;
128 }
129 ptr = reinterpret_cast<uintptr_t>(result);
130 if ((ptr & (alignment-1)) != 0) {
131 ptr += alignment - (ptr & (alignment-1));
132 }
133 return reinterpret_cast<void*>(ptr);
134}
135
136#endif /* HAVE(SBRK) */
137
138#if HAVE(MMAP)
139
140static void* TryMmap(size_t size, size_t alignment) {
141 // Enforce page alignment
142 if (pagesize == 0) pagesize = getpagesize();
143 if (alignment < pagesize) alignment = pagesize;
144 size = ((size + alignment - 1) / alignment) * alignment;
145
146 // Ask for extra memory if alignment > pagesize
147 size_t extra = 0;
148 if (alignment > pagesize) {
149 extra = alignment - pagesize;
150 }
151 void* result = mmap(NULL, size + extra,
152 PROT_READ|PROT_WRITE,
153 MAP_PRIVATE|MAP_ANONYMOUS,
154 -1, 0);
155 if (result == reinterpret_cast<void*>(MAP_FAILED)) {
156 mmap_failure = true;
157 return NULL;
158 }
159
160 // Adjust the return memory so it is aligned
161 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
162 size_t adjust = 0;
163 if ((ptr & (alignment - 1)) != 0) {
164 adjust = alignment - (ptr & (alignment - 1));
165 }
166
167 // Return the unused memory to the system
168 if (adjust > 0) {
169 munmap(reinterpret_cast<void*>(ptr), adjust);
170 }
171 if (adjust < extra) {
172 munmap(reinterpret_cast<void*>(ptr + adjust + size), extra - adjust);
173 }
174
175 ptr += adjust;
176 return reinterpret_cast<void*>(ptr);
177}
178
179#endif /* HAVE(MMAP) */
180
181#if HAVE(VIRTUALALLOC)
182
183static void* TryVirtualAlloc(size_t size, size_t alignment) {
184 // Enforce page alignment
185 if (pagesize == 0) {
186 SYSTEM_INFO system_info;
187 GetSystemInfo(&system_info);
188 pagesize = system_info.dwPageSize;
189 }
190 if (alignment < pagesize) alignment = pagesize;
191 size = ((size + alignment - 1) / alignment) * alignment;
192
193 // Ask for extra memory if alignment > pagesize
194 size_t extra = 0;
195 if (alignment > pagesize) {
196 extra = alignment - pagesize;
197 }
198 void* result = VirtualAlloc(NULL, size + extra,
199 MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
200 PAGE_READWRITE);
201
202 if (result == NULL) {
203 VirtualAlloc_failure = true;
204 return NULL;
205 }
206
207 // Adjust the return memory so it is aligned
208 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
209 size_t adjust = 0;
210 if ((ptr & (alignment - 1)) != 0) {
211 adjust = alignment - (ptr & (alignment - 1));
212 }
213
214 // Return the unused memory to the system - we'd like to release but the best we can do
215 // is decommit, since Windows only lets you free the whole allocation.
216 if (adjust > 0) {
217 VirtualFree(reinterpret_cast<void*>(ptr), adjust, MEM_DECOMMIT);
218 }
219 if (adjust < extra) {
220 VirtualFree(reinterpret_cast<void*>(ptr + adjust + size), extra-adjust, MEM_DECOMMIT);
221 }
222
223 ptr += adjust;
224 return reinterpret_cast<void*>(ptr);
225}
226
227#endif /* HAVE(MMAP) */
228
229#ifndef WTF_CHANGES
230static void* TryDevMem(size_t size, size_t alignment) {
231 static bool initialized = false;
232 static off_t physmem_base; // next physical memory address to allocate
233 static off_t physmem_limit; // maximum physical address allowed
234 static int physmem_fd; // file descriptor for /dev/mem
235
236 // Check if we should use /dev/mem allocation. Note that it may take
237 // a while to get this flag initialized, so meanwhile we fall back to
238 // the next allocator. (It looks like 7MB gets allocated before
239 // this flag gets initialized -khr.)
240 if (FLAGS_malloc_devmem_start == 0) {
241 // NOTE: not a devmem_failure - we'd like TCMalloc_SystemAlloc to
242 // try us again next time.
243 return NULL;
244 }
245
246 if (!initialized) {
247 physmem_fd = open("/dev/mem", O_RDWR);
248 if (physmem_fd < 0) {
249 devmem_failure = true;
250 return NULL;
251 }
252 physmem_base = FLAGS_malloc_devmem_start*1024LL*1024LL;
253 physmem_limit = FLAGS_malloc_devmem_limit*1024LL*1024LL;
254 initialized = true;
255 }
256
257 // Enforce page alignment
258 if (pagesize == 0) pagesize = getpagesize();
259 if (alignment < pagesize) alignment = pagesize;
260 size = ((size + alignment - 1) / alignment) * alignment;
261
262 // Ask for extra memory if alignment > pagesize
263 size_t extra = 0;
264 if (alignment > pagesize) {
265 extra = alignment - pagesize;
266 }
267
268 // check to see if we have any memory left
269 if (physmem_limit != 0 && physmem_base + size + extra > physmem_limit) {
270 devmem_failure = true;
271 return NULL;
272 }
273 void *result = mmap(0, size + extra, PROT_WRITE|PROT_READ,
274 MAP_SHARED, physmem_fd, physmem_base);
275 if (result == reinterpret_cast<void*>(MAP_FAILED)) {
276 devmem_failure = true;
277 return NULL;
278 }
279 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
280
281 // Adjust the return memory so it is aligned
282 size_t adjust = 0;
283 if ((ptr & (alignment - 1)) != 0) {
284 adjust = alignment - (ptr & (alignment - 1));
285 }
286
287 // Return the unused virtual memory to the system
288 if (adjust > 0) {
289 munmap(reinterpret_cast<void*>(ptr), adjust);
290 }
291 if (adjust < extra) {
292 munmap(reinterpret_cast<void*>(ptr + adjust + size), extra - adjust);
293 }
294
295 ptr += adjust;
296 physmem_base += adjust + size;
297
298 return reinterpret_cast<void*>(ptr);
299}
300#endif
301
302void* TCMalloc_SystemAlloc(size_t size, size_t alignment) {
303#ifndef WTF_CHANGES
304 if (TCMallocDebug::level >= TCMallocDebug::kVerbose) {
305 MESSAGE("TCMalloc_SystemAlloc(%" PRIuS ", %" PRIuS")\n",
306 size, alignment);
307 }
308#endif
309 SpinLockHolder lock_holder(&spinlock);
310
311 // Enforce minimum alignment
312 if (alignment < sizeof(MemoryAligner)) alignment = sizeof(MemoryAligner);
313
314 // Try twice, once avoiding allocators that failed before, and once
315 // more trying all allocators even if they failed before.
316 for (int i = 0; i < 2; i++) {
317
318#ifndef WTF_CHANGES
319 if (use_devmem && !devmem_failure) {
320 void* result = TryDevMem(size, alignment);
321 if (result != NULL) return result;
322 }
323#endif
324
325#if HAVE(SBRK)
326 if (use_sbrk && !sbrk_failure) {
327 void* result = TrySbrk(size, alignment);
328 if (result != NULL) return result;
329 }
330#endif
331
332#if HAVE(MMAP)
333 if (use_mmap && !mmap_failure) {
334 void* result = TryMmap(size, alignment);
335 if (result != NULL) return result;
336 }
337#endif
338
339#if HAVE(VIRTUALALLOC)
340 if (use_VirtualAlloc && !VirtualAlloc_failure) {
341 void* result = TryVirtualAlloc(size, alignment);
342 if (result != NULL) return result;
343 }
344#endif
345
346 // nothing worked - reset failure flags and try again
347 devmem_failure = false;
348 sbrk_failure = false;
349 mmap_failure = false;
350 VirtualAlloc_failure = false;
351 }
352 return NULL;
353}
Note: See TracBrowser for help on using the repository browser.