blob: e61c08739eba6c409ea339d8eda19cecf79f6583 [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2// Copyright (c) 2005, Google Inc.
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// ---
32// Author: Sanjay Ghemawat
33
34#include <config.h>
35#include <errno.h> // for EAGAIN, errno
36#include <fcntl.h> // for open, O_RDWR
37#include <stddef.h> // for size_t, NULL, ptrdiff_t
38#if defined HAVE_STDINT_H
39#include <stdint.h> // for uintptr_t, intptr_t
40#elif defined HAVE_INTTYPES_H
41#include <inttypes.h>
42#else
43#include <sys/types.h>
44#endif
45#ifdef HAVE_MMAP
46#include <sys/mman.h> // for munmap, mmap, MADV_DONTNEED, etc
47#endif
48#ifdef HAVE_UNISTD_H
49#include <unistd.h> // for sbrk, getpagesize, off_t
50#endif
51#include <new> // for operator new
52#include <gperftools/malloc_extension.h>
53#include "base/basictypes.h"
54#include "base/commandlineflags.h"
55#include "base/spinlock.h" // for SpinLockHolder, SpinLock, etc
56#include "common.h"
57#include "internal_logging.h"
58
59// On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old
60// form of the name instead.
61#ifndef MAP_ANONYMOUS
62# define MAP_ANONYMOUS MAP_ANON
63#endif
64
65// MADV_FREE is specifically designed for use by malloc(), but only
66// FreeBSD supports it; in linux we fall back to the somewhat inferior
67// MADV_DONTNEED.
68#if !defined(MADV_FREE) && defined(MADV_DONTNEED)
69# define MADV_FREE MADV_DONTNEED
70#endif
71
72// Solaris has a bug where it doesn't declare madvise() for C++.
73// http://www.opensolaris.org/jive/thread.jspa?threadID=21035&tstart=0
74#if defined(__sun) && defined(__SVR4)
75# include <sys/types.h> // for caddr_t
76 extern "C" { extern int madvise(caddr_t, size_t, int); }
77#endif
78
79// Set kDebugMode mode so that we can have use C++ conditionals
80// instead of preprocessor conditionals.
81#ifdef NDEBUG
82static const bool kDebugMode = false;
83#else
84static const bool kDebugMode = true;
85#endif
86
87// TODO(sanjay): Move the code below into the tcmalloc namespace
88using tcmalloc::kLog;
89using tcmalloc::Log;
90
91// Anonymous namespace to avoid name conflicts on "CheckAddressBits".
92namespace {
93
94// Check that no bit is set at position ADDRESS_BITS or higher.
95template <int ADDRESS_BITS> bool CheckAddressBits(uintptr_t ptr) {
96 return (ptr >> ADDRESS_BITS) == 0;
97}
98
99// Specialize for the bit width of a pointer to avoid undefined shift.
100template <> bool CheckAddressBits<8 * sizeof(void*)>(uintptr_t ptr) {
101 return true;
102}
103
104} // Anonymous namespace to avoid name conflicts on "CheckAddressBits".
105
106COMPILE_ASSERT(kAddressBits <= 8 * sizeof(void*),
107 address_bits_larger_than_pointer_size);
108
109// Structure for discovering alignment
110union MemoryAligner {
111 void* p;
112 double d;
113 size_t s;
114} CACHELINE_ALIGNED;
115
116static SpinLock spinlock(SpinLock::LINKER_INITIALIZED);
117
118#if defined(HAVE_MMAP) || defined(MADV_FREE)
119// Page size is initialized on demand (only needed for mmap-based allocators)
120static size_t pagesize = 0;
121#endif
122
123// The current system allocator
124SysAllocator* sys_alloc = NULL;
125
126// Number of bytes taken from system.
127size_t TCMalloc_SystemTaken = 0;
128
129// Configuration parameters.
130DEFINE_int32(malloc_devmem_start,
131 EnvToInt("TCMALLOC_DEVMEM_START", 0),
132 "Physical memory starting location in MB for /dev/mem allocation."
133 " Setting this to 0 disables /dev/mem allocation");
134DEFINE_int32(malloc_devmem_limit,
135 EnvToInt("TCMALLOC_DEVMEM_LIMIT", 0),
136 "Physical memory limit location in MB for /dev/mem allocation."
137 " Setting this to 0 means no limit.");
138DEFINE_bool(malloc_skip_sbrk,
139 EnvToBool("TCMALLOC_SKIP_SBRK", false),
140 "Whether sbrk can be used to obtain memory.");
141DEFINE_bool(malloc_skip_mmap,
142 EnvToBool("TCMALLOC_SKIP_MMAP", false),
143 "Whether mmap can be used to obtain memory.");
144DEFINE_bool(malloc_disable_memory_release,
145 EnvToBool("TCMALLOC_DISABLE_MEMORY_RELEASE", false),
146 "Whether MADV_FREE/MADV_DONTNEED should be used"
147 " to return unused memory to the system.");
148
149// static allocators
150class SbrkSysAllocator : public SysAllocator {
151public:
152 SbrkSysAllocator() : SysAllocator() {
153 }
154 void* Alloc(size_t size, size_t *actual_size, size_t alignment);
155};
156static char sbrk_space[sizeof(SbrkSysAllocator)];
157
158class MmapSysAllocator : public SysAllocator {
159public:
160 MmapSysAllocator() : SysAllocator() {
161 }
162 void* Alloc(size_t size, size_t *actual_size, size_t alignment);
163};
164static char mmap_space[sizeof(MmapSysAllocator)];
165
166class DevMemSysAllocator : public SysAllocator {
167public:
168 DevMemSysAllocator() : SysAllocator() {
169 }
170 void* Alloc(size_t size, size_t *actual_size, size_t alignment);
171};
172
173class DefaultSysAllocator : public SysAllocator {
174 public:
175 DefaultSysAllocator() : SysAllocator() {
176 for (int i = 0; i < kMaxAllocators; i++) {
177 failed_[i] = true;
178 allocs_[i] = NULL;
179 names_[i] = NULL;
180 }
181 }
182 void SetChildAllocator(SysAllocator* alloc, unsigned int index,
183 const char* name) {
184 if (index < kMaxAllocators && alloc != NULL) {
185 allocs_[index] = alloc;
186 failed_[index] = false;
187 names_[index] = name;
188 }
189 }
190 void* Alloc(size_t size, size_t *actual_size, size_t alignment);
191
192 private:
193 static const int kMaxAllocators = 2;
194 bool failed_[kMaxAllocators];
195 SysAllocator* allocs_[kMaxAllocators];
196 const char* names_[kMaxAllocators];
197};
198static char default_space[sizeof(DefaultSysAllocator)];
199static const char sbrk_name[] = "SbrkSysAllocator";
200static const char mmap_name[] = "MmapSysAllocator";
201
202
203void* SbrkSysAllocator::Alloc(size_t size, size_t *actual_size,
204 size_t alignment) {
205#if !defined(HAVE_SBRK) || defined(__UCLIBC__)
206 return NULL;
207#else
208 // Check if we should use sbrk allocation.
209 // FLAGS_malloc_skip_sbrk starts out as false (its uninitialized
210 // state) and eventually gets initialized to the specified value. Note
211 // that this code runs for a while before the flags are initialized.
212 // That means that even if this flag is set to true, some (initial)
213 // memory will be allocated with sbrk before the flag takes effect.
214 if (FLAGS_malloc_skip_sbrk) {
215 return NULL;
216 }
217
218 // sbrk will release memory if passed a negative number, so we do
219 // a strict check here
220 if (static_cast<ptrdiff_t>(size + alignment) < 0) return NULL;
221
222 // This doesn't overflow because TCMalloc_SystemAlloc has already
223 // tested for overflow at the alignment boundary.
224 size = ((size + alignment - 1) / alignment) * alignment;
225
226 // "actual_size" indicates that the bytes from the returned pointer
227 // p up to and including (p + actual_size - 1) have been allocated.
228 if (actual_size) {
229 *actual_size = size;
230 }
231
232 // Check that we we're not asking for so much more memory that we'd
233 // wrap around the end of the virtual address space. (This seems
234 // like something sbrk() should check for us, and indeed opensolaris
235 // does, but glibc does not:
236 // http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libc/port/sys/sbrk.c?a=true
237 // http://sourceware.org/cgi-bin/cvsweb.cgi/~checkout~/libc/misc/sbrk.c?rev=1.1.2.1&content-type=text/plain&cvsroot=glibc
238 // Without this check, sbrk may succeed when it ought to fail.)
239 if (reinterpret_cast<intptr_t>(sbrk(0)) + size < size) {
240 return NULL;
241 }
242
243 void* result = sbrk(size);
244 if (result == reinterpret_cast<void*>(-1)) {
245 return NULL;
246 }
247
248 // Is it aligned?
249 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
250 if ((ptr & (alignment-1)) == 0) return result;
251
252 // Try to get more memory for alignment
253 size_t extra = alignment - (ptr & (alignment-1));
254 void* r2 = sbrk(extra);
255 if (reinterpret_cast<uintptr_t>(r2) == (ptr + size)) {
256 // Contiguous with previous result
257 return reinterpret_cast<void*>(ptr + extra);
258 }
259
260 // Give up and ask for "size + alignment - 1" bytes so
261 // that we can find an aligned region within it.
262 result = sbrk(size + alignment - 1);
263 if (result == reinterpret_cast<void*>(-1)) {
264 return NULL;
265 }
266 ptr = reinterpret_cast<uintptr_t>(result);
267 if ((ptr & (alignment-1)) != 0) {
268 ptr += alignment - (ptr & (alignment-1));
269 }
270 return reinterpret_cast<void*>(ptr);
271#endif // HAVE_SBRK
272}
273
274void* MmapSysAllocator::Alloc(size_t size, size_t *actual_size,
275 size_t alignment) {
276#ifndef HAVE_MMAP
277 return NULL;
278#else
279 // Check if we should use mmap allocation.
280 // FLAGS_malloc_skip_mmap starts out as false (its uninitialized
281 // state) and eventually gets initialized to the specified value. Note
282 // that this code runs for a while before the flags are initialized.
283 // Chances are we never get here before the flags are initialized since
284 // sbrk is used until the heap is exhausted (before mmap is used).
285 if (FLAGS_malloc_skip_mmap) {
286 return NULL;
287 }
288
289 // Enforce page alignment
290 if (pagesize == 0) pagesize = getpagesize();
291 if (alignment < pagesize) alignment = pagesize;
292 size_t aligned_size = ((size + alignment - 1) / alignment) * alignment;
293 if (aligned_size < size) {
294 return NULL;
295 }
296 size = aligned_size;
297
298 // "actual_size" indicates that the bytes from the returned pointer
299 // p up to and including (p + actual_size - 1) have been allocated.
300 if (actual_size) {
301 *actual_size = size;
302 }
303
304 // Ask for extra memory if alignment > pagesize
305 size_t extra = 0;
306 if (alignment > pagesize) {
307 extra = alignment - pagesize;
308 }
309
310 // Note: size + extra does not overflow since:
311 // size + alignment < (1<<NBITS).
312 // and extra <= alignment
313 // therefore size + extra < (1<<NBITS)
314 void* result = mmap(NULL, size + extra,
315 PROT_READ|PROT_WRITE,
316 MAP_PRIVATE|MAP_ANONYMOUS,
317 -1, 0);
318 if (result == reinterpret_cast<void*>(MAP_FAILED)) {
319 return NULL;
320 }
321
322 // Adjust the return memory so it is aligned
323 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
324 size_t adjust = 0;
325 if ((ptr & (alignment - 1)) != 0) {
326 adjust = alignment - (ptr & (alignment - 1));
327 }
328
329 // Return the unused memory to the system
330 if (adjust > 0) {
331 munmap(reinterpret_cast<void*>(ptr), adjust);
332 }
333 if (adjust < extra) {
334 munmap(reinterpret_cast<void*>(ptr + adjust + size), extra - adjust);
335 }
336
337 ptr += adjust;
338 return reinterpret_cast<void*>(ptr);
339#endif // HAVE_MMAP
340}
341
342void* DevMemSysAllocator::Alloc(size_t size, size_t *actual_size,
343 size_t alignment) {
344#ifndef HAVE_MMAP
345 return NULL;
346#else
347 static bool initialized = false;
348 static off_t physmem_base; // next physical memory address to allocate
349 static off_t physmem_limit; // maximum physical address allowed
350 static int physmem_fd; // file descriptor for /dev/mem
351
352 // Check if we should use /dev/mem allocation. Note that it may take
353 // a while to get this flag initialized, so meanwhile we fall back to
354 // the next allocator. (It looks like 7MB gets allocated before
355 // this flag gets initialized -khr.)
356 if (FLAGS_malloc_devmem_start == 0) {
357 // NOTE: not a devmem_failure - we'd like TCMalloc_SystemAlloc to
358 // try us again next time.
359 return NULL;
360 }
361
362 if (!initialized) {
363 physmem_fd = open("/dev/mem", O_RDWR);
364 if (physmem_fd < 0) {
365 return NULL;
366 }
367 physmem_base = FLAGS_malloc_devmem_start*1024LL*1024LL;
368 physmem_limit = FLAGS_malloc_devmem_limit*1024LL*1024LL;
369 initialized = true;
370 }
371
372 // Enforce page alignment
373 if (pagesize == 0) pagesize = getpagesize();
374 if (alignment < pagesize) alignment = pagesize;
375 size_t aligned_size = ((size + alignment - 1) / alignment) * alignment;
376 if (aligned_size < size) {
377 return NULL;
378 }
379 size = aligned_size;
380
381 // "actual_size" indicates that the bytes from the returned pointer
382 // p up to and including (p + actual_size - 1) have been allocated.
383 if (actual_size) {
384 *actual_size = size;
385 }
386
387 // Ask for extra memory if alignment > pagesize
388 size_t extra = 0;
389 if (alignment > pagesize) {
390 extra = alignment - pagesize;
391 }
392
393 // check to see if we have any memory left
394 if (physmem_limit != 0 &&
395 ((size + extra) > (physmem_limit - physmem_base))) {
396 return NULL;
397 }
398
399 // Note: size + extra does not overflow since:
400 // size + alignment < (1<<NBITS).
401 // and extra <= alignment
402 // therefore size + extra < (1<<NBITS)
403 void *result = mmap(0, size + extra, PROT_WRITE|PROT_READ,
404 MAP_SHARED, physmem_fd, physmem_base);
405 if (result == reinterpret_cast<void*>(MAP_FAILED)) {
406 return NULL;
407 }
408 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
409
410 // Adjust the return memory so it is aligned
411 size_t adjust = 0;
412 if ((ptr & (alignment - 1)) != 0) {
413 adjust = alignment - (ptr & (alignment - 1));
414 }
415
416 // Return the unused virtual memory to the system
417 if (adjust > 0) {
418 munmap(reinterpret_cast<void*>(ptr), adjust);
419 }
420 if (adjust < extra) {
421 munmap(reinterpret_cast<void*>(ptr + adjust + size), extra - adjust);
422 }
423
424 ptr += adjust;
425 physmem_base += adjust + size;
426
427 return reinterpret_cast<void*>(ptr);
428#endif // HAVE_MMAP
429}
430
431void* DefaultSysAllocator::Alloc(size_t size, size_t *actual_size,
432 size_t alignment) {
433 for (int i = 0; i < kMaxAllocators; i++) {
434 if (!failed_[i] && allocs_[i] != NULL) {
435 void* result = allocs_[i]->Alloc(size, actual_size, alignment);
436 if (result != NULL) {
437 return result;
438 }
439 failed_[i] = true;
440 }
441 }
442 // After both failed, reset "failed_" to false so that a single failed
443 // allocation won't make the allocator never work again.
444 for (int i = 0; i < kMaxAllocators; i++) {
445 failed_[i] = false;
446 }
447 return NULL;
448}
449
450ATTRIBUTE_WEAK ATTRIBUTE_NOINLINE
451SysAllocator *tc_get_sysalloc_override(SysAllocator *def)
452{
453 return def;
454}
455
456static bool system_alloc_inited = false;
457void InitSystemAllocators(void) {
458 MmapSysAllocator *mmap = new (mmap_space) MmapSysAllocator();
459 SbrkSysAllocator *sbrk = new (sbrk_space) SbrkSysAllocator();
460
461 // In 64-bit debug mode, place the mmap allocator first since it
462 // allocates pointers that do not fit in 32 bits and therefore gives
463 // us better testing of code's 64-bit correctness. It also leads to
464 // less false negatives in heap-checking code. (Numbers are less
465 // likely to look like pointers and therefore the conservative gc in
466 // the heap-checker is less likely to misinterpret a number as a
467 // pointer).
468 DefaultSysAllocator *sdef = new (default_space) DefaultSysAllocator();
469 if (kDebugMode && sizeof(void*) > 4) {
470 sdef->SetChildAllocator(mmap, 0, mmap_name);
471 sdef->SetChildAllocator(sbrk, 1, sbrk_name);
472 } else {
473 sdef->SetChildAllocator(sbrk, 0, sbrk_name);
474 sdef->SetChildAllocator(mmap, 1, mmap_name);
475 }
476
477 sys_alloc = tc_get_sysalloc_override(sdef);
478}
479
480void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size,
481 size_t alignment) {
482 // Discard requests that overflow
483 if (size + alignment < size) return NULL;
484
485 SpinLockHolder lock_holder(&spinlock);
486
487 if (!system_alloc_inited) {
488 InitSystemAllocators();
489 system_alloc_inited = true;
490 }
491
492 // Enforce minimum alignment
493 if (alignment < sizeof(MemoryAligner)) alignment = sizeof(MemoryAligner);
494
495 size_t actual_size_storage;
496 if (actual_size == NULL) {
497 actual_size = &actual_size_storage;
498 }
499
500 void* result = sys_alloc->Alloc(size, actual_size, alignment);
501 if (result != NULL) {
502 CHECK_CONDITION(
503 CheckAddressBits<kAddressBits>(
504 reinterpret_cast<uintptr_t>(result) + *actual_size - 1));
505 TCMalloc_SystemTaken += *actual_size;
506 }
507 return result;
508}
509
510bool TCMalloc_SystemRelease(void* start, size_t length) {
511#ifdef MADV_FREE
512 if (FLAGS_malloc_devmem_start) {
513 // It's not safe to use MADV_FREE/MADV_DONTNEED if we've been
514 // mapping /dev/mem for heap memory.
515 return false;
516 }
517 if (FLAGS_malloc_disable_memory_release) return false;
518 if (pagesize == 0) pagesize = getpagesize();
519 const size_t pagemask = pagesize - 1;
520
521 size_t new_start = reinterpret_cast<size_t>(start);
522 size_t end = new_start + length;
523 size_t new_end = end;
524
525 // Round up the starting address and round down the ending address
526 // to be page aligned:
527 new_start = (new_start + pagesize - 1) & ~pagemask;
528 new_end = new_end & ~pagemask;
529
530 ASSERT((new_start & pagemask) == 0);
531 ASSERT((new_end & pagemask) == 0);
532 ASSERT(new_start >= reinterpret_cast<size_t>(start));
533 ASSERT(new_end <= end);
534
535 if (new_end > new_start) {
536 int result;
537 do {
538 result = madvise(reinterpret_cast<char*>(new_start),
539 new_end - new_start, MADV_FREE);
540 } while (result == -1 && errno == EAGAIN);
541
542 return result != -1;
543 }
544#endif
545 return false;
546}
547
548void TCMalloc_SystemCommit(void* start, size_t length) {
549 // Nothing to do here. TCMalloc_SystemRelease does not alter pages
550 // such that they need to be re-committed before they can be used by the
551 // application.
552}