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); |
- } |
- } |
-} |