summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--Makefile.in2
-rw-r--r--doc/tcmalloc.html7
-rw-r--r--src/debugallocation.cc13
-rw-r--r--src/heap-checker.cc32
-rw-r--r--src/memfs_malloc.cc9
-rwxr-xr-xsrc/pprof37
-rw-r--r--src/tcmalloc.cc147
-rwxr-xr-xsrc/tests/debugallocation_test.sh2
-rw-r--r--src/tests/memalign_unittest.cc4
-rw-r--r--src/tests/tcmalloc_unittest.cc14
-rw-r--r--src/thread_cache.cc29
12 files changed, 216 insertions, 82 deletions
diff --git a/Makefile.am b/Makefile.am
index a8a2527..327d98a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -24,7 +24,7 @@ AM_CXXFLAGS =
# changes one day. gcc ignores functions it doesn't understand.
if GCC
AM_CXXFLAGS += -Wall -Wwrite-strings -Woverloaded-virtual \
- -Wno-sign-compare -Wno-unused-result \
+ -Wno-sign-compare \
-fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc \
-fno-builtin-calloc -fno-builtin-cfree \
-fno-builtin-memalign -fno-builtin-posix_memalign \
diff --git a/Makefile.in b/Makefile.in
index e173564..339f47f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -52,7 +52,7 @@ host_triplet = @host@
# builtins now in any case, but it's best to be explicit in case that
# changes one day. gcc ignores functions it doesn't understand.
@GCC_TRUE@am__append_2 = -Wall -Wwrite-strings -Woverloaded-virtual \
-@GCC_TRUE@ -Wno-sign-compare -Wno-unused-result \
+@GCC_TRUE@ -Wno-sign-compare \
@GCC_TRUE@ -fno-builtin-malloc -fno-builtin-free -fno-builtin-realloc \
@GCC_TRUE@ -fno-builtin-calloc -fno-builtin-cfree \
@GCC_TRUE@ -fno-builtin-memalign -fno-builtin-posix_memalign \
diff --git a/doc/tcmalloc.html b/doc/tcmalloc.html
index 9d7ab7e..4578984 100644
--- a/doc/tcmalloc.html
+++ b/doc/tcmalloc.html
@@ -604,6 +604,13 @@ tries to allocate memory from the kernel.</p>
</td>
</tr>
+<tr valign=top>
+ <td><code>TCMALLOC_MEMFS_MAP_PRVIATE</code></td>
+ <td>default: false</td>
+ <td>
+ If true, use MAP_PRIVATE when mapping via memfs, not MAP_SHARED.
+ </td>
+</tr>
</table>
diff --git a/src/debugallocation.cc b/src/debugallocation.cc
index 12865eb..d38d1e0 100644
--- a/src/debugallocation.cc
+++ b/src/debugallocation.cc
@@ -36,10 +36,10 @@
// Malloc can be in several places on older versions of OS X.
# if defined(HAVE_MALLOC_H)
# include <malloc.h>
-# elif defined(HAVE_SYS_MALLOC_H)
-# include <sys/malloc.h>
# elif defined(HAVE_MALLOC_MALLOC_H)
# include <malloc/malloc.h>
+# elif defined(HAVE_SYS_MALLOC_H)
+# include <sys/malloc.h>
# endif
#endif
#include <pthread.h>
@@ -1404,7 +1404,14 @@ extern "C" PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW {
#endif
extern "C" PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) __THROW {
- return BASE_MALLOC_SIZE(ptr);
+ if (!ptr) {
+ return 0;
+ }
+ MallocBlock* mb = MallocBlock::FromRawPointer(ptr);
+ // This is just to make sure we actually own mb (and ptr). We don't
+ // use the actual value, just the 'exception' it raises on error.
+ (void)BASE_MALLOC_SIZE(mb);
+ return mb->data_size();
}
// Override __libc_memalign in libc on linux boxes.
diff --git a/src/heap-checker.cc b/src/heap-checker.cc
index dfda9ad..1794e8b 100644
--- a/src/heap-checker.cc
+++ b/src/heap-checker.cc
@@ -882,6 +882,8 @@ HeapLeakChecker::ProcMapsResult HeapLeakChecker::UseProcMapsLocked(
int64 inode;
char *permissions, *filename;
bool saw_shared_lib = false;
+ bool saw_nonzero_inode = false;
+ bool saw_shared_lib_with_nonzero_inode = false;
while (it.Next(&start_address, &end_address, &permissions,
&file_offset, &inode, &filename)) {
if (start_address >= end_address) {
@@ -897,16 +899,22 @@ HeapLeakChecker::ProcMapsResult HeapLeakChecker::UseProcMapsLocked(
// do things in this loop.
continue;
}
- // Determine if any shared libraries are present. This is the same
- // list of extensions as is found in pprof.
- if (strstr(filename, ".dll")) { // for windows, which doesn't have inodes
+ // Determine if any shared libraries are present (this is the same
+ // list of extensions as is found in pprof). We want to ignore
+ // 'fake' libraries with inode 0 when determining. However, some
+ // systems don't share inodes via /proc, so we turn off this check
+ // if we don't see any evidence that we're getting inode info.
+ if (inode != 0) {
+ saw_nonzero_inode = true;
+ }
+ if ((strstr(filename, "lib") && strstr(filename, ".so")) ||
+ strstr(filename, ".dll") ||
+ // not all .dylib filenames start with lib. .dylib is big enough
+ // that we are unlikely to get false matches just checking that.
+ strstr(filename, ".dylib") || strstr(filename, ".bundle")) {
saw_shared_lib = true;
- } else if (inode != 0) { // ignore fake files
- if ((strstr(filename, "lib") && strstr(filename, ".so")) ||
- // not all .dylib filenames start with lib. .dylib is big enough
- // that we are unlikely to get false matches just checking that.
- strstr(filename, ".dylib") || strstr(filename, ".bundle")) {
- saw_shared_lib = true;
+ if (inode != 0) {
+ saw_shared_lib_with_nonzero_inode = true;
}
}
@@ -927,6 +935,12 @@ HeapLeakChecker::ProcMapsResult HeapLeakChecker::UseProcMapsLocked(
RAW_CHECK(0, "");
}
}
+ // If /proc/self/maps is reporting inodes properly (we saw a
+ // non-zero inode), then we only say we saw a shared lib if we saw a
+ // 'real' one, with a non-zero inode.
+ if (saw_nonzero_inode) {
+ saw_shared_lib = saw_shared_lib_with_nonzero_inode;
+ }
if (!saw_shared_lib) {
RAW_LOG(ERROR, "No shared libs detected. Will likely report false leak "
"positives for statically linked executables.");
diff --git a/src/memfs_malloc.cc b/src/memfs_malloc.cc
index 9df4cad..210a4ee 100644
--- a/src/memfs_malloc.cc
+++ b/src/memfs_malloc.cc
@@ -71,6 +71,9 @@ DEFINE_bool(memfs_malloc_abort_on_fail,
DEFINE_bool(memfs_malloc_ignore_mmap_fail,
EnvToBool("TCMALLOC_MEMFS_IGNORE_MMAP_FAIL", false),
"Ignore failures from mmap");
+DEFINE_bool(memfs_malloc_map_private,
+ EnvToBool("TCMALLOC_MEMFS_MAP_PRIVATE", false),
+ "Use MAP_PRIVATE with mmap");
// Hugetlbfs based allocator for tcmalloc
class HugetlbSysAllocator: public SysAllocator {
@@ -162,8 +165,10 @@ void* HugetlbSysAllocator::Alloc(size_t size, size_t *actual_size,
// size + alignment < (1<<NBITS).
// and extra <= alignment
// therefore size + extra < (1<<NBITS)
- void *result = mmap(0, size + extra, PROT_WRITE|PROT_READ,
- MAP_SHARED, hugetlb_fd_, hugetlb_base_);
+ void *result;
+ result = mmap(0, size + extra, PROT_WRITE|PROT_READ,
+ FLAGS_memfs_malloc_map_private ? MAP_PRIVATE : MAP_SHARED,
+ hugetlb_fd_, hugetlb_base_);
if (result == reinterpret_cast<void*>(MAP_FAILED)) {
if (!FLAGS_memfs_malloc_ignore_mmap_fail) {
TCMalloc_MESSAGE(__FILE__, __LINE__, "mmap of size %"PRIuS" failed: %s\n",
diff --git a/src/pprof b/src/pprof
index 7a20df3..03bafa4 100755
--- a/src/pprof
+++ b/src/pprof
@@ -122,6 +122,11 @@ my $UNKNOWN_BINARY = "(unknown)";
# 64-bit profiles. To err on the safe size, default to 64-bit here:
my $address_length = 16;
+my $dev_null = "/dev/null";
+if (! -e $dev_null && $^O =~ /MSWin/) { # $^O is the OS perl was built for
+ $dev_null = "nul";
+}
+
# A list of paths to search for shared object files
my @prefix_list = ();
@@ -705,7 +710,7 @@ sub ReadlineMightFail {
sub RunGV {
my $fname = shift;
my $bg = shift; # "" or " &" if we should run in background
- if (!system("$GV --version >/dev/null 2>&1")) {
+ if (!system("$GV --version >$dev_null 2>&1")) {
# Options using double dash are supported by this gv version.
# Also, turn on noantialias to better handle bug in gv for
# postscript files with large dimensions.
@@ -4261,7 +4266,7 @@ sub MapToSymbols {
# If "addr2line" isn't installed on the system at all, just use
# nm to get what info we can (function names, but not line numbers).
- if (system("$addr2line --help >/dev/null 2>&1") != 0) {
+ if (system("$addr2line --help >$dev_null 2>&1") != 0) {
MapSymbolsWithNM($image, $offset, $pclist, $symbols);
return;
}
@@ -4279,7 +4284,7 @@ sub MapToSymbols {
if (defined($sep_address)) {
# Only add " -i" to addr2line if the binary supports it.
# addr2line --help returns 0, but not if it sees an unknown flag first.
- if (system("$cmd -i --help >/dev/null 2>&1") == 0) {
+ if (system("$cmd -i --help >$dev_null 2>&1") == 0) {
$cmd .= " -i";
} else {
$sep_address = undef; # no need for sep_address if we don't support -i
@@ -4425,8 +4430,16 @@ sub ConfigureObjTools {
# predictably return error status in prod.
(-e $prog_file) || error("$prog_file does not exist.\n");
- # Follow symlinks (at least for systems where "file" supports that)
- my $file_type = `/usr/bin/file -L $prog_file 2>/dev/null || /usr/bin/file $prog_file`;
+ my $file_type = undef;
+ if (-e "/usr/bin/file") {
+ # Follow symlinks (at least for systems where "file" supports that).
+ $file_type = `/usr/bin/file -L $prog_file 2>$dev_null || /usr/bin/file $prog_file`;
+ } elsif ($^O == "MSWin32") {
+ $file_type = "MS Windows";
+ } else {
+ print STDERR "WARNING: Can't determine the file type of $prog_file";
+ }
+
if ($file_type =~ /64-bit/) {
# Change $address_length to 16 if the program file is ELF 64-bit.
# We can't detect this from many (most?) heap or lock contention
@@ -4638,16 +4651,16 @@ sub GetProcedureBoundaries {
# --demangle and -f.
my $demangle_flag = "";
my $cppfilt_flag = "";
- if (system("$nm --demangle $image >/dev/null 2>&1") == 0) {
+ if (system("$nm --demangle $image >$dev_null 2>&1") == 0) {
# In this mode, we do "nm --demangle <foo>"
$demangle_flag = "--demangle";
$cppfilt_flag = "";
- } elsif (system("$cppfilt $image >/dev/null 2>&1") == 0) {
+ } elsif (system("$cppfilt $image >$dev_null 2>&1") == 0) {
# In this mode, we do "nm <foo> | c++filt"
$cppfilt_flag = " | $cppfilt";
};
my $flatten_flag = "";
- if (system("$nm -f $image >/dev/null 2>&1") == 0) {
+ if (system("$nm -f $image >$dev_null 2>&1") == 0) {
$flatten_flag = "-f";
}
@@ -4655,11 +4668,11 @@ sub GetProcedureBoundaries {
# -D to at least get *exported* symbols. If we can't use --demangle,
# we use c++filt instead, if it exists on this system.
my @nm_commands = ("$nm -n $flatten_flag $demangle_flag" .
- " $image 2>/dev/null $cppfilt_flag",
+ " $image 2>$dev_null $cppfilt_flag",
"$nm -D -n $flatten_flag $demangle_flag" .
- " $image 2>/dev/null $cppfilt_flag",
+ " $image 2>$dev_null $cppfilt_flag",
# 6nm is for Go binaries
- "6nm $image 2>/dev/null | sort",
+ "6nm $image 2>$dev_null | sort",
);
# If the executable is an MS Windows PDB-format executable, we'll
@@ -4668,7 +4681,7 @@ sub GetProcedureBoundaries {
# PDB-format executables can apparently include dwarf .o files.
if (exists $obj_tool_map{"nm_pdb"}) {
my $nm_pdb = $obj_tool_map{"nm_pdb"};
- push(@nm_commands, "$nm_pdb --demangle $image 2>/dev/null");
+ push(@nm_commands, "$nm_pdb --demangle $image 2>$dev_null");
}
foreach my $nm_command (@nm_commands) {
diff --git a/src/tcmalloc.cc b/src/tcmalloc.cc
index b037f57..ab3f03b 100644
--- a/src/tcmalloc.cc
+++ b/src/tcmalloc.cc
@@ -97,15 +97,15 @@
#else
#include <sys/types.h>
#endif
-// We only need malloc.h for struct mallinfo.
-#ifdef HAVE_STRUCT_MALLINFO
+// We only need malloc.h for struct mallinfo and for apple builds
+#if defined(HAVE_STRUCT_MALLINFO) || defined(__APPLE__)
// Malloc can be in several places on older versions of OS X.
# if defined(HAVE_MALLOC_H)
# include <malloc.h>
-# elif defined(HAVE_SYS_MALLOC_H)
-# include <sys/malloc.h>
# elif defined(HAVE_MALLOC_MALLOC_H)
# include <malloc/malloc.h>
+# elif defined(HAVE_SYS_MALLOC_H)
+# include <sys/malloc.h>
# endif
#endif
#include <string.h>
@@ -262,14 +262,116 @@ extern "C" {
} // extern "C"
#endif // #ifndef _WIN32
+// We define this here because one some architectures it's needed soon.
+namespace {
+inline size_t GetSizeWithCallback(void* ptr,
+ size_t (*invalid_getsize_fn)(void*)) {
+ if (ptr == NULL)
+ return 0;
+ const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
+ size_t cl = Static::pageheap()->GetSizeClassIfCached(p);
+ if (cl != 0) {
+ return Static::sizemap()->ByteSizeForClass(cl);
+ } else {
+ Span *span = Static::pageheap()->GetDescriptor(p);
+ if (span == NULL) { // means we do not own this memory
+ return (*invalid_getsize_fn)(ptr);
+ } else if (span->sizeclass != 0) {
+ Static::pageheap()->CacheSizeClass(p, span->sizeclass);
+ return Static::sizemap()->ByteSizeForClass(span->sizeclass);
+ } else {
+ return span->length << kPageShift;
+ }
+ }
+}
+}
+
// Override the libc functions to prefer our own instead. This comes
-// first so code in tcmalloc.cc can use the overridden versions. One
-// exception: in windows, by default, we patch our code into these
+// first so code in tcmalloc.cc can use the overridden versions.
+#if defined(WIN32_DO_PATCHING)
+
+// One exception: in windows, by default, we patch our code into these
// functions (via src/windows/patch_function.cc) rather than override
// them. In that case, we don't want to do this overriding here.
-#if !defined(WIN32_DO_PATCHING)
-#if defined(__GNUC__) && !defined(__MACH__)
+#elif defined(__APPLE__)
+
+// Mach's two-level naming scheme makes aliasing difficult, but we can
+// use apple's malloc_default_zone() to replace the system alloc.
+// http://www.opensource.apple.com/source/Libc/Libc-583/include/malloc/malloc.h
+// http://www.opensource.apple.com/source/Libc/Libc-583/gen/malloc.c
+// We need wrappers for all the routines, sadly. :-(
+
+// malloc_zone semantics are we return 0 if we don't own the memory.
+static size_t mz_invalid_getsize(void*) {
+ return 0;
+}
+static size_t mz_size(malloc_zone_t* zone, const void* ptr) {
+ // TODO(csilvers): change this method to take a const void*, one day.
+ // TODO(csilvers): this is totally wrong with debugallocation.
+ return GetSizeWithCallback(const_cast<void*>(ptr), mz_invalid_getsize);
+}
+static void* mz_malloc(malloc_zone_t* zone, size_t size) {
+ return tc_malloc(size);
+}
+static void* mz_calloc(malloc_zone_t* zone, size_t num_items, size_t size) {
+ return tc_calloc(num_items, size);
+}
+static void* mz_valloc(malloc_zone_t* zone, size_t size) {
+ return tc_valloc(size);
+}
+static void mz_free(malloc_zone_t* zone, void* ptr) {
+ return tc_free(ptr);
+}
+static void* mz_realloc(malloc_zone_t* zone, void* ptr, size_t size) {
+ return tc_realloc(ptr, size);
+}
+static void mz_destroy(malloc_zone_t* zone) {
+ // A no-op -- we will not be destroyed!
+}
+
+static void ReplaceSystemAlloc() {
+ static malloc_zone_t system_zone_copy;
+ malloc_zone_t* system_zone = malloc_default_zone();
+ memcpy(&system_zone_copy, system_zone, sizeof(system_zone_copy));
+
+ system_zone->zone_name = "tcmalloc";
+ system_zone->size = &mz_size;
+ system_zone->malloc = &mz_malloc;
+ system_zone->calloc = &mz_calloc;
+ system_zone->valloc = &mz_valloc;
+ system_zone->free = &mz_free;
+ system_zone->realloc = &mz_realloc;
+ system_zone->destroy = &mz_destroy;
+ // TODO(csilvers): figure out if this version of malloc.h supports
+ // batch_malloc, batch_free, memalign, and free_definite_size, and
+ // set those to NULL if so.
+
+ // Now register the old system zone, so allocations that happened
+ // before we ran this command can still be executed.
+ malloc_zone_register(&system_zone_copy);
+}
+#define HAVE_REPLACE_SYSTEM_ALLOC 1
+
+// OS X doesn't have memalign, posix_memalign, pvalloc, or cfree, so
+// we can just define our own. :-)
+extern "C" {
+ void cfree(void* p) __THROW { tc_cfree(p); }
+ void* memalign(size_t a, size_t s) __THROW { return tc_memalign(a, s); }
+ void* pvalloc(size_t s) __THROW { return tc_pvalloc(s); }
+ int posix_memalign(void** r, size_t a, size_t s) __THROW {
+ return tc_posix_memalign(r, a, s);
+ }
+ void malloc_stats(void) __THROW { tc_malloc_stats(); }
+ int mallopt(int cmd, int v) __THROW { return tc_mallopt(cmd, v); }
+#ifdef HAVE_STRUCT_MALLINFO
+ struct mallinfo mallinfo(void) __THROW { return tc_mallinfo(); }
+#endif
+ // An alias for malloc_size(), which os x defines.
+ size_t malloc_usable_size(void* p) __THROW { return tc_malloc_size(p); }
+} // extern "C"
+
+#elif defined(__GNUC__) && !defined(__MACH__)
// Potentially faster variants that use the gcc alias extension.
// FreeBSD does support aliases, but apparently not correctly. :-(
// NOTE: we make many of these symbols weak, but do so in the makefile
@@ -344,7 +446,8 @@ extern "C" {
size_t malloc_size(void* p) __THROW { return tc_malloc_size(p); }
size_t malloc_usable_size(void* p) __THROW { return tc_malloc_size(p); }
} // extern "C"
-#endif // #if defined(__GNUC__)
+
+#endif // #if defined(WIN32_DO_PATCHING) ...
// Some library routines on RedHat 9 allocate memory using malloc()
// and free it using __libc_free() (or vice-versa). Since we provide
@@ -381,8 +484,6 @@ extern "C" {
#undef ALIAS
-#endif // #ifndef(WIN32_DO_PATCHING)
-
// ----------------------- IMPLEMENTATION -------------------------------
@@ -912,6 +1013,9 @@ TCMallocGuard::TCMallocGuard() {
// patch the windows VirtualAlloc, etc.
PatchWindowsFunctions(); // defined in windows/patch_functions.cc
#endif
+#ifdef HAVE_REPLACE_SYSTEM_ALLOC
+ ReplaceSystemAlloc(); // for OS X
+#endif
tc_free(tc_malloc(1));
ThreadCache::InitTSD();
tc_free(tc_malloc(1));
@@ -1169,27 +1273,6 @@ inline void do_free(void* ptr) {
return do_free_with_callback(ptr, &InvalidFree);
}
-inline size_t GetSizeWithCallback(void* ptr,
- size_t (*invalid_getsize_fn)(void*)) {
- if (ptr == NULL)
- return 0;
- const PageID p = reinterpret_cast<uintptr_t>(ptr) >> kPageShift;
- size_t cl = Static::pageheap()->GetSizeClassIfCached(p);
- if (cl != 0) {
- return Static::sizemap()->ByteSizeForClass(cl);
- } else {
- Span *span = Static::pageheap()->GetDescriptor(p);
- if (span == NULL) { // means we do not own this memory
- return (*invalid_getsize_fn)(ptr);
- } else if (span->sizeclass != 0) {
- Static::pageheap()->CacheSizeClass(p, span->sizeclass);
- return Static::sizemap()->ByteSizeForClass(span->sizeclass);
- } else {
- return span->length << kPageShift;
- }
- }
-}
-
// This lets you call back to a given function pointer if ptr is invalid.
// It is used primarily by windows code which wants a specialized callback.
inline void* do_realloc_with_callback(
diff --git a/src/tests/debugallocation_test.sh b/src/tests/debugallocation_test.sh
index 5d9bd8b..faa6c79 100755
--- a/src/tests/debugallocation_test.sh
+++ b/src/tests/debugallocation_test.sh
@@ -65,7 +65,7 @@ OneDeathTest() {
}
death_test_num=0 # which death test to run
-while /bin/true; do
+while :; do # same as 'while true', but more portable
echo -n "Running death test $death_test_num..."
output="`OneDeathTest $death_test_num`"
case $output in
diff --git a/src/tests/memalign_unittest.cc b/src/tests/memalign_unittest.cc
index ce2c1f3..1b707dd 100644
--- a/src/tests/memalign_unittest.cc
+++ b/src/tests/memalign_unittest.cc
@@ -60,10 +60,10 @@
// Malloc can be in several places on older versions of OS X.
#if defined(HAVE_MALLOC_H)
#include <malloc.h> // for memalign() and valloc()
-#elif defined(HAVE_SYS_MALLOC_H)
-#include <sys/malloc.h>
#elif defined(HAVE_MALLOC_MALLOC_H)
#include <malloc/malloc.h>
+#elif defined(HAVE_SYS_MALLOC_H)
+#include <sys/malloc.h>
#endif
#include "base/basictypes.h"
#include "base/logging.h"
diff --git a/src/tests/tcmalloc_unittest.cc b/src/tests/tcmalloc_unittest.cc
index 7c21fc4..3af48f8 100644
--- a/src/tests/tcmalloc_unittest.cc
+++ b/src/tests/tcmalloc_unittest.cc
@@ -1015,7 +1015,10 @@ static int RunAllTests(int argc, char** argv) {
p1 = calloc(10, 2);
CHECK(p1 != NULL);
VerifyNewHookWasCalled();
- p1 = realloc(p1, 30);
+ // We make sure we realloc to a big size, since some systems (OS
+ // X) will notice if the realloced size continues to fit into the
+ // malloc-block and make this a noop if so.
+ p1 = realloc(p1, 30000);
CHECK(p1 != NULL);
VerifyNewHookWasCalled();
VerifyDeleteHookWasCalled();
@@ -1092,6 +1095,15 @@ static int RunAllTests(int argc, char** argv) {
::operator delete(p2, std::nothrow);
VerifyDeleteHookWasCalled();
+ // Try strdup(), which the system allocates but we must free. If
+ // all goes well, libc will use our malloc!
+ p2 = strdup("test");
+ CHECK(p2 != NULL);
+ VerifyNewHookWasCalled();
+ free(p2);
+ VerifyDeleteHookWasCalled();
+
+
// Test mmap too: both anonymous mmap and mmap of a file
// Note that for right now we only override mmap on linux
// systems, so those are the only ones for which we check.
diff --git a/src/thread_cache.cc b/src/thread_cache.cc
index 8d31117..64e3b07 100644
--- a/src/thread_cache.cc
+++ b/src/thread_cache.cc
@@ -312,16 +312,6 @@ void ThreadCache::InitTSD() {
ASSERT(!tsd_inited_);
perftools_pthread_key_create(&heap_key_, DestroyThreadCache);
tsd_inited_ = true;
-
- // We may have used a fake pthread_t for the main thread. Fix it.
- pthread_t zero;
- memset(&zero, 0, sizeof(zero));
- SpinLockHolder h(Static::pageheap_lock());
- for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) {
- if (h->tid_ == zero) {
- h->tid_ = pthread_self();
- }
- }
}
ThreadCache* ThreadCache::CreateCacheIfNecessary() {
@@ -329,14 +319,17 @@ ThreadCache* ThreadCache::CreateCacheIfNecessary() {
ThreadCache* heap = NULL;
{
SpinLockHolder h(Static::pageheap_lock());
-
- // Early on in glibc's life, we cannot even call pthread_self()
- pthread_t me;
- if (!tsd_inited_) {
- memset(&me, 0, sizeof(me));
- } else {
- me = pthread_self();
- }
+ // On very old libc's, this call may crash if it happens too
+ // early. No libc using NPTL should be affected. If there
+ // is a crash here, we could use code (on linux, at least)
+ // to detect NPTL vs LinuxThreads:
+ // http://www.redhat.com/archives/phil-list/2003-April/msg00038.html
+ // If we detect not-NPTL, we could execute the old code from
+ // http://google-perftools.googlecode.com/svn/tags/google-perftools-1.7/src/thread_cache.cc
+ // that avoids calling pthread_self too early. The problem with
+ // that code is it caused a race condition when tcmalloc is linked
+ // in statically and other libraries spawn threads before main.
+ const pthread_t me = pthread_self();
// This may be a recursive malloc call from pthread_setspecific()
// In that case, the heap for this thread has already been created