| Index: third_party/tcmalloc/chromium/src/system-alloc.cc
|
| ===================================================================
|
| --- third_party/tcmalloc/chromium/src/system-alloc.cc (revision 88335)
|
| +++ third_party/tcmalloc/chromium/src/system-alloc.cc (working copy)
|
| @@ -31,26 +31,29 @@
|
| // Author: Sanjay Ghemawat
|
|
|
| #include <config.h>
|
| +#include <errno.h> // for EAGAIN, errno
|
| +#include <fcntl.h> // for open, O_RDWR
|
| +#include <stddef.h> // for size_t, NULL, ptrdiff_t
|
| #if defined HAVE_STDINT_H
|
| -#include <stdint.h>
|
| +#include <stdint.h> // for uintptr_t, intptr_t
|
| #elif defined HAVE_INTTYPES_H
|
| #include <inttypes.h>
|
| #else
|
| #include <sys/types.h>
|
| #endif
|
| +#ifdef HAVE_MMAP
|
| +#include <sys/mman.h> // for munmap, mmap, MADV_DONTNEED, etc
|
| +#endif
|
| #ifdef HAVE_UNISTD_H
|
| -#include <unistd.h>
|
| +#include <unistd.h> // for sbrk, getpagesize, off_t
|
| #endif
|
| -#include <fcntl.h> // for open()
|
| -#ifdef HAVE_MMAP
|
| -#include <sys/mman.h>
|
| -#endif
|
| -#include <errno.h>
|
| -#include "system-alloc.h"
|
| +#include <new> // for operator new
|
| +#include <google/malloc_extension.h>
|
| +#include "base/basictypes.h"
|
| +#include "base/commandlineflags.h"
|
| +#include "base/spinlock.h" // for SpinLockHolder, SpinLock, etc
|
| +#include "common.h"
|
| #include "internal_logging.h"
|
| -#include "base/logging.h"
|
| -#include "base/commandlineflags.h"
|
| -#include "base/spinlock.h"
|
|
|
| // On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old
|
| // form of the name instead.
|
| @@ -73,6 +76,24 @@
|
| static const bool kDebugMode = true;
|
| #endif
|
|
|
| +// Anonymous namespace to avoid name conflicts on "CheckAddressBits".
|
| +namespace {
|
| +
|
| +// Check that no bit is set at position ADDRESS_BITS or higher.
|
| +template <int ADDRESS_BITS> bool CheckAddressBits(uintptr_t ptr) {
|
| + return (ptr >> ADDRESS_BITS) == 0;
|
| +}
|
| +
|
| +// Specialize for the bit width of a pointer to avoid undefined shift.
|
| +template <> bool CheckAddressBits<8 * sizeof(void*)>(uintptr_t ptr) {
|
| + return true;
|
| +}
|
| +
|
| +} // Anonymous namespace to avoid name conflicts on "CheckAddressBits".
|
| +
|
| +COMPILE_ASSERT(kAddressBits <= 8 * sizeof(void*),
|
| + address_bits_larger_than_pointer_size);
|
| +
|
| // Structure for discovering alignment
|
| union MemoryAligner {
|
| void* p;
|
| @@ -87,8 +108,10 @@
|
| static size_t pagesize = 0;
|
| #endif
|
|
|
| +// The current system allocator
|
| +SysAllocator* sys_alloc = NULL;
|
| +
|
| // Configuration parameters.
|
| -
|
| DEFINE_int32(malloc_devmem_start,
|
| EnvToInt("TCMALLOC_DEVMEM_START", 0),
|
| "Physical memory starting location in MB for /dev/mem allocation."
|
| @@ -110,7 +133,7 @@
|
| SbrkSysAllocator() : SysAllocator() {
|
| }
|
| void* Alloc(size_t size, size_t *actual_size, size_t alignment);
|
| - void DumpStats(TCMalloc_Printer* printer);
|
| + void FlagsInitialized() {}
|
| };
|
| static char sbrk_space[sizeof(SbrkSysAllocator)];
|
|
|
| @@ -119,7 +142,7 @@
|
| MmapSysAllocator() : SysAllocator() {
|
| }
|
| void* Alloc(size_t size, size_t *actual_size, size_t alignment);
|
| - void DumpStats(TCMalloc_Printer* printer);
|
| + void FlagsInitialized() {}
|
| };
|
| static char mmap_space[sizeof(MmapSysAllocator)];
|
|
|
| @@ -128,30 +151,41 @@
|
| DevMemSysAllocator() : SysAllocator() {
|
| }
|
| void* Alloc(size_t size, size_t *actual_size, size_t alignment);
|
| - void DumpStats(TCMalloc_Printer* printer);
|
| + void FlagsInitialized() {}
|
| };
|
| -static char devmem_space[sizeof(DevMemSysAllocator)];
|
|
|
| -static const int kStaticAllocators = 3;
|
| -// kMaxDynamicAllocators + kStaticAllocators;
|
| -static const int kMaxAllocators = 5;
|
| -static SysAllocator *allocators[kMaxAllocators];
|
| +class DefaultSysAllocator : public SysAllocator {
|
| + public:
|
| + DefaultSysAllocator() : SysAllocator() {
|
| + for (int i = 0; i < kMaxAllocators; i++) {
|
| + failed_[i] = true;
|
| + allocs_[i] = NULL;
|
| + }
|
| + }
|
| + void SetChildAllocator(SysAllocator* alloc, unsigned int index,
|
| + const char* name) {
|
| + if (index < kMaxAllocators && alloc != NULL) {
|
| + allocs_[index] = alloc;
|
| + failed_[index] = false;
|
| + }
|
| + }
|
| + void* Alloc(size_t size, size_t *actual_size, size_t alignment);
|
| + void FlagsInitialized() {}
|
|
|
| -bool RegisterSystemAllocator(SysAllocator *a, int priority) {
|
| - SpinLockHolder lock_holder(&spinlock);
|
| + private:
|
| + static const int kMaxAllocators = 2;
|
| + bool failed_[kMaxAllocators];
|
| + SysAllocator* allocs_[kMaxAllocators];
|
| + const char* names_[kMaxAllocators];
|
| +};
|
| +static char default_space[sizeof(DefaultSysAllocator)];
|
| +static const char sbrk_name[] = "SbrkSysAllocator";
|
| +static const char mmap_name[] = "MmapSysAllocator";
|
|
|
| - // No two allocators should have a priority conflict, since the order
|
| - // is determined at compile time.
|
| - CHECK_CONDITION(allocators[priority] == NULL);
|
| - allocators[priority] = a;
|
| - return true;
|
| -}
|
|
|
| -
|
| void* SbrkSysAllocator::Alloc(size_t size, size_t *actual_size,
|
| size_t alignment) {
|
| #ifndef HAVE_SBRK
|
| - failed_ = true;
|
| return NULL;
|
| #else
|
| // Check if we should use sbrk allocation.
|
| @@ -186,13 +220,11 @@
|
| // http://sourceware.org/cgi-bin/cvsweb.cgi/~checkout~/libc/misc/sbrk.c?rev=1.1.2.1&content-type=text/plain&cvsroot=glibc
|
| // Without this check, sbrk may succeed when it ought to fail.)
|
| if (reinterpret_cast<intptr_t>(sbrk(0)) + size < size) {
|
| - failed_ = true;
|
| return NULL;
|
| }
|
|
|
| void* result = sbrk(size);
|
| if (result == reinterpret_cast<void*>(-1)) {
|
| - failed_ = true;
|
| return NULL;
|
| }
|
|
|
| @@ -212,7 +244,6 @@
|
| // that we can find an aligned region within it.
|
| result = sbrk(size + alignment - 1);
|
| if (result == reinterpret_cast<void*>(-1)) {
|
| - failed_ = true;
|
| return NULL;
|
| }
|
| ptr = reinterpret_cast<uintptr_t>(result);
|
| @@ -223,14 +254,9 @@
|
| #endif // HAVE_SBRK
|
| }
|
|
|
| -void SbrkSysAllocator::DumpStats(TCMalloc_Printer* printer) {
|
| - printer->printf("SbrkSysAllocator: failed_=%d\n", failed_);
|
| -}
|
| -
|
| void* MmapSysAllocator::Alloc(size_t size, size_t *actual_size,
|
| size_t alignment) {
|
| #ifndef HAVE_MMAP
|
| - failed_ = true;
|
| return NULL;
|
| #else
|
| // Check if we should use mmap allocation.
|
| @@ -273,7 +299,6 @@
|
| MAP_PRIVATE|MAP_ANONYMOUS,
|
| -1, 0);
|
| if (result == reinterpret_cast<void*>(MAP_FAILED)) {
|
| - failed_ = true;
|
| return NULL;
|
| }
|
|
|
| @@ -297,14 +322,9 @@
|
| #endif // HAVE_MMAP
|
| }
|
|
|
| -void MmapSysAllocator::DumpStats(TCMalloc_Printer* printer) {
|
| - printer->printf("MmapSysAllocator: failed_=%d\n", failed_);
|
| -}
|
| -
|
| void* DevMemSysAllocator::Alloc(size_t size, size_t *actual_size,
|
| size_t alignment) {
|
| #ifndef HAVE_MMAP
|
| - failed_ = true;
|
| return NULL;
|
| #else
|
| static bool initialized = false;
|
| @@ -325,7 +345,6 @@
|
| if (!initialized) {
|
| physmem_fd = open("/dev/mem", O_RDWR);
|
| if (physmem_fd < 0) {
|
| - failed_ = true;
|
| return NULL;
|
| }
|
| physmem_base = FLAGS_malloc_devmem_start*1024LL*1024LL;
|
| @@ -357,7 +376,6 @@
|
| // check to see if we have any memory left
|
| if (physmem_limit != 0 &&
|
| ((size + extra) > (physmem_limit - physmem_base))) {
|
| - failed_ = true;
|
| return NULL;
|
| }
|
|
|
| @@ -368,7 +386,6 @@
|
| void *result = mmap(0, size + extra, PROT_WRITE|PROT_READ,
|
| MAP_SHARED, physmem_fd, physmem_base);
|
| if (result == reinterpret_cast<void*>(MAP_FAILED)) {
|
| - failed_ = true;
|
| return NULL;
|
| }
|
| uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
|
| @@ -394,15 +411,30 @@
|
| #endif // HAVE_MMAP
|
| }
|
|
|
| -void DevMemSysAllocator::DumpStats(TCMalloc_Printer* printer) {
|
| - printer->printf("DevMemSysAllocator: failed_=%d\n", failed_);
|
| +void* DefaultSysAllocator::Alloc(size_t size, size_t *actual_size,
|
| + size_t alignment) {
|
| + for (int i = 0; i < kMaxAllocators; i++) {
|
| + if (!failed_[i] && allocs_[i] != NULL) {
|
| + void* result = allocs_[i]->Alloc(size, actual_size, alignment);
|
| + if (result != NULL) {
|
| + return result;
|
| + }
|
| + TCMalloc_MESSAGE(__FILE__, __LINE__, "%s failed.\n", names_[i]);
|
| + failed_[i] = true;
|
| + }
|
| + }
|
| + // After both failed, reset "failed_" to false so that a single failed
|
| + // allocation won't make the allocator never work again.
|
| + for (int i = 0; i < kMaxAllocators; i++) {
|
| + failed_[i] = false;
|
| + }
|
| + return NULL;
|
| }
|
|
|
| static bool system_alloc_inited = false;
|
| void InitSystemAllocators(void) {
|
| - // This determines the order in which system allocators are called
|
| - int i = kMaxDynamicAllocators;
|
| - allocators[i++] = new (devmem_space) DevMemSysAllocator();
|
| + MmapSysAllocator *mmap = new (mmap_space) MmapSysAllocator();
|
| + SbrkSysAllocator *sbrk = new (sbrk_space) SbrkSysAllocator();
|
|
|
| // In 64-bit debug mode, place the mmap allocator first since it
|
| // allocates pointers that do not fit in 32 bits and therefore gives
|
| @@ -411,13 +443,15 @@
|
| // likely to look like pointers and therefore the conservative gc in
|
| // the heap-checker is less likely to misinterpret a number as a
|
| // pointer).
|
| + DefaultSysAllocator *sdef = new (default_space) DefaultSysAllocator();
|
| if (kDebugMode && sizeof(void*) > 4) {
|
| - allocators[i++] = new (mmap_space) MmapSysAllocator();
|
| - allocators[i++] = new (sbrk_space) SbrkSysAllocator();
|
| + sdef->SetChildAllocator(mmap, 0, mmap_name);
|
| + sdef->SetChildAllocator(sbrk, 1, sbrk_name);
|
| } else {
|
| - allocators[i++] = new (sbrk_space) SbrkSysAllocator();
|
| - allocators[i++] = new (mmap_space) MmapSysAllocator();
|
| + sdef->SetChildAllocator(sbrk, 0, sbrk_name);
|
| + sdef->SetChildAllocator(mmap, 1, mmap_name);
|
| }
|
| + sys_alloc = sdef;
|
| }
|
|
|
| void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size,
|
| @@ -435,26 +469,17 @@
|
| // Enforce minimum alignment
|
| if (alignment < sizeof(MemoryAligner)) alignment = sizeof(MemoryAligner);
|
|
|
| - // Try twice, once avoiding allocators that failed before, and once
|
| - // more trying all allocators even if they failed before.
|
| - for (int i = 0; i < 2; i++) {
|
| - for (int j = 0; j < kMaxAllocators; j++) {
|
| - SysAllocator *a = allocators[j];
|
| - if (a == NULL) continue;
|
| - if (a->usable_ && !a->failed_) {
|
| - void* result = a->Alloc(size, actual_size, alignment);
|
| - if (result != NULL) return result;
|
| - }
|
| + void* result = sys_alloc->Alloc(size, actual_size, alignment);
|
| + if (result != NULL) {
|
| + if (actual_size) {
|
| + CheckAddressBits<kAddressBits>(
|
| + reinterpret_cast<uintptr_t>(result) + *actual_size - 1);
|
| + } else {
|
| + CheckAddressBits<kAddressBits>(
|
| + reinterpret_cast<uintptr_t>(result) + size - 1);
|
| }
|
| -
|
| - // nothing worked - reset failed_ flags and try again
|
| - for (int j = 0; j < kMaxAllocators; j++) {
|
| - SysAllocator *a = allocators[j];
|
| - if (a == NULL) continue;
|
| - a->failed_ = false;
|
| - }
|
| }
|
| - return NULL;
|
| + return result;
|
| }
|
|
|
| void TCMalloc_SystemRelease(void* start, size_t length) {
|
| @@ -498,13 +523,3 @@
|
| // such that they need to be re-committed before they can be used by the
|
| // application.
|
| }
|
| -
|
| -void DumpSystemAllocatorStats(TCMalloc_Printer* printer) {
|
| - for (int j = 0; j < kMaxAllocators; j++) {
|
| - SysAllocator *a = allocators[j];
|
| - if (a == NULL) continue;
|
| - if (a->usable_) {
|
| - a->DumpStats(printer);
|
| - }
|
| - }
|
| -}
|
|
|