amputate maybe_threads

This facility allowed us to build tcmalloc without linking in actual
-lpthread. Via weak symbols we checked at runtime if pthread functions
are available and if not, special single-threaded stubs were used
instead. Not always brining in pthread dependency helped performance
of some programs or libraries which depended at runtime on whether
threads are linked or not. Most notable of those are libstdc++ which
uses non-atomic refcounting on single threaded programs.

But such optional dependency on pthreads caused complications for
nearly no benefit. One trouble was reported in github issue #1110.

This days glibc/libstdc++ combo actually depends on
sys/single_threaded.h facility. So bringing pthread at runtime is
fine. Also modern glibc ships pthread symbols inside libc anyways and
libpthread is empty. I also found that for whatever reason on BSDs and
osx we already pulled in proper pthreads too.

So we loose nothing and we get issue #1110 fixed. And we simplify
everything.
This commit is contained in:
Aliaksey Kandratsenka 2023-07-14 02:19:21 -04:00
parent 3cd265b05a
commit 46d3315ad7
17 changed files with 24 additions and 381 deletions

1
.gitignore vendored
View File

@ -77,7 +77,6 @@
/malloc_hook_test.exe
/markidle_unittest
/markidle_unittest.exe
/maybe_threads_unittest.sh
/memalign_debug_unittest
/memalign_unittest
/missing

View File

@ -410,12 +410,6 @@ if(EXISTS /usr/sfw/lib/libstdc++.la)
endif()
endif()
check_cxx_source_compiles(
"#include <string>
#include <vector>
int main() { pthread_t th; pthread_join(th, 0); return 0; }"
have_pthread_despite_asking_for)
check_variable_exists("program_invocation_name" HAVE_PROGRAM_INVOCATION_NAME)
if(MINGW)
@ -572,10 +566,6 @@ if(MINGW OR MSVC)
# (We do this via a #pragma for msvc, but need to do it here for mingw).
target_link_libraries(sysinfo shlwapi)
if(have_pthread_despite_asking_for)
add_library(maybe_threads STATIC src/maybe_threads.cc)
set(maybe_threads_lib maybe_threads)
endif()
else()
set(SPINLOCK_INCLUDES src/base/spinlock.h
src/base/spinlock_internal.h)
@ -588,8 +578,6 @@ else()
set(TCMALLOC_CC "src/tcmalloc.cc")
set(SYSTEM_ALLOC_CC "src/system-alloc.cc")
add_library(maybe_threads STATIC src/maybe_threads.cc)
set(maybe_threads_lib maybe_threads)
endif()
if(BUILD_TESTING)
@ -614,7 +602,7 @@ if(BUILD_TESTING)
# By default, MallocHook takes stack traces for use by the heap-checker.
# We don't need that functionality here, so we turn it off to reduce deps.
target_compile_definitions(low_level_alloc_unittest PRIVATE NO_TCMALLOC_SAMPLES)
target_link_libraries(low_level_alloc_unittest spinlock sysinfo logging ${maybe_threads_lib})
target_link_libraries(low_level_alloc_unittest spinlock sysinfo logging)
add_test(low_level_alloc_unittest low_level_alloc_unittest)
endif()
@ -745,7 +733,7 @@ add_library(tcmalloc_minimal_internal_object OBJECT ${libtcmalloc_minimal_intern
# We #define NO_TCMALLOC_SAMPLES, since sampling is turned off for _minimal.
target_compile_definitions(tcmalloc_minimal_internal_object PRIVATE NO_TCMALLOC_SAMPLES NO_HEAP_CHECK NDEBUG)
add_library(tcmalloc_minimal_internal INTERFACE)
target_link_libraries(tcmalloc_minimal_internal INTERFACE ${LIBSPINLOCK} ${maybe_threads_lib})
target_link_libraries(tcmalloc_minimal_internal INTERFACE ${LIBSPINLOCK})
target_sources(tcmalloc_minimal_internal INTERFACE $<TARGET_OBJECTS:tcmalloc_minimal_internal_object>)
set(libtcmalloc_minimal_la_SOURCES ${TCMALLOC_CC} ${TCMALLOC_MINIMAL_INCLUDES})
@ -815,13 +803,6 @@ if(BUILD_TESTING)
tcmalloc_minimal_large_heap_fragmentation_unittest PUBLIC tcmalloc_minimal)
add_test(tcmalloc_minimal_large_heap_fragmentation_unittest tcmalloc_minimal_large_heap_fragmentation_unittest)
if(BUILD_SHARED_LIBS AND NOT MINGW)
add_custom_target(maybe_threads_unittest
COMMAND src/tests/maybe_threads_unittest.sh
VERBATIM)
add_test(maybe_threads_unittest maybe_threads_unittest)
endif()
if(MINGW OR MSVC)
set(port_src src/windows/port.cc)
endif()
@ -1064,7 +1045,7 @@ if(GPERFTOOLS_BUILD_HEAP_CHECKER OR GPERFTOOLS_BUILD_HEAP_PROFILER)
set(libtcmalloc_la_SOURCES ${TCMALLOC_CC} ${TCMALLOC_INCLUDES})
set(libtcmalloc_la_DEFINE NDEBUG ${EMERGENCY_MALLOC_DEFINE})
set(libtcmalloc_la_LIBADD tcmalloc_internal ${maybe_threads_lib} Threads::Threads)
set(libtcmalloc_la_LIBADD tcmalloc_internal Threads::Threads)
if(GPERFTOOLS_BUILD_HEAP_CHECKER)
# heap-checker-bcad is last, in hopes its global ctor will run first.
# (Note this is added to libtcmalloc.la, not libtcmalloc_internal.la,
@ -1282,7 +1263,7 @@ if(GPERFTOOLS_BUILD_CPU_PROFILER)
src/profile-handler.cc
src/profiledata.cc
${CPU_PROFILER_INCLUDES})
set(libprofiler_la_LIBADD stacktrace ${maybe_threads_lib} fake_stacktrace_scope)
set(libprofiler_la_LIBADD stacktrace fake_stacktrace_scope)
add_library(profiler SHARED ${libprofiler_la_SOURCES})
target_link_libraries(profiler PRIVATE ${libprofiler_la_LIBADD})
set_target_properties(profiler PROPERTIES

View File

@ -249,7 +249,7 @@ above, by linking in libtcmalloc_minimal.
libtcmalloc.so successfully builds, and the "advanced" tcmalloc
functionality all works except for the leak-checker, which has
Linux-specific code:
% make heap-profiler_unittest.sh maybe_threads_unittest.sh \
% make heap-profiler_unittest.sh \
tcmalloc_unittest tcmalloc_both_unittest \
tcmalloc_large_unittest # THESE WORK
% make -k heap-checker_unittest.sh \

View File

@ -168,10 +168,6 @@ libsysinfo_la_SOURCES = src/base/sysinfo.cc \
$(SYSINFO_INCLUDES)
libsysinfo_la_LIBADD = $(NANOSLEEP_LIBS)
noinst_LTLIBRARIES += libmaybe_threads.la
# .cc is conditionally added below
libmaybe_threads_la_SOURCES = src/maybe_threads.h
# For MinGW, we use also have to use libwindows Luckily, we need the
# windows.a library in exactly the same place we need spinlock.a
# (pretty much everywhere), so we can use the same variable name for
@ -227,10 +223,6 @@ libsysinfo_la_LIBADD += -lshlwapi
# patch_functions.cc #includes tcmalloc.cc, so no need to link it in.
TCMALLOC_CC =
# windows has its own system for threads and system memory allocation.
if HAVE_PTHREAD_DESPITE_ASKING_FOR
libmaybe_threads_la_SOURCES += src/maybe_threads.cc
endif
SYSTEM_ALLOC_CC =
else !MINGW
SPINLOCK_INCLUDES = src/base/spinlock.h \
@ -245,7 +237,6 @@ libspinlock_la_LIBADD = $(NANOSLEEP_LIBS)
LIBSPINLOCK = libspinlock.la libsysinfo.la liblogging.la
TCMALLOC_CC = src/tcmalloc.cc
libmaybe_threads_la_SOURCES += src/maybe_threads.cc
SYSTEM_ALLOC_CC = src/system-alloc.cc
endif !MINGW
@ -276,7 +267,7 @@ low_level_alloc_unittest_SOURCES = src/base/low_level_alloc.cc \
# By default, MallocHook takes stack traces for use by the heap-checker.
# We don't need that functionality here, so we turn it off to reduce deps.
low_level_alloc_unittest_CXXFLAGS = -DNO_TCMALLOC_SAMPLES
low_level_alloc_unittest_LDADD = $(LIBSPINLOCK) libmaybe_threads.la
low_level_alloc_unittest_LDADD = $(LIBSPINLOCK)
### ------- stack trace
@ -439,7 +430,7 @@ libtcmalloc_minimal_internal_la_CXXFLAGS = -DNO_TCMALLOC_SAMPLES \
-DNDEBUG \
$(AM_CXXFLAGS)
libtcmalloc_minimal_internal_la_LDFLAGS = $(AM_LDFLAGS)
libtcmalloc_minimal_internal_la_LIBADD = $(LIBSPINLOCK) libmaybe_threads.la
libtcmalloc_minimal_internal_la_LIBADD = $(LIBSPINLOCK)
lib_LTLIBRARIES += libtcmalloc_minimal.la
WINDOWS_PROJECTS += vsprojects/libtcmalloc_minimal/libtcmalloc_minimal.vcxproj
@ -474,11 +465,9 @@ LIBS_TO_WEAKEN += libtcmalloc_minimal.la
## src/malloc_hook_mmap_linux.h \
## src/malloc_hook_mmap_freebsd.h \
## src/base/basictypes.h \
## src/maybe_threads.h
## malloc_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
## src/malloc_hook.cc \
## src/malloc_extension.cc \
## $(MAYBE_THREADS_CC) \
## $(MALLOC_UNITTEST_INCLUDES)
## malloc_unittest_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
## malloc_unittest_LDFLAGS = $(PTHREAD_CFLAGS)
@ -512,7 +501,7 @@ tcm_min_asserts_unittest_SOURCES = src/tests/tcmalloc_unittest.cc \
tcm_min_asserts_unittest_CXXFLAGS = -DNO_TCMALLOC_SAMPLES -DNO_HEAP_CHECK \
$(PTHREAD_CFLAGS) $(AM_CXXFLAGS)
tcm_min_asserts_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
tcm_min_asserts_unittest_LDADD = $(LIBSPINLOCK) libmaybe_threads.la \
tcm_min_asserts_unittest_LDADD = $(LIBSPINLOCK) \
liblogging.la $(PTHREAD_LIBS)
TESTS += tcmalloc_minimal_large_unittest
@ -528,27 +517,6 @@ tcmalloc_minimal_large_heap_fragmentation_unittest_CXXFLAGS = $(PTHREAD_CFLAGS)
tcmalloc_minimal_large_heap_fragmentation_unittest_LDFLAGS = $(PTHREAD_CFLAGS) $(TCMALLOC_FLAGS)
tcmalloc_minimal_large_heap_fragmentation_unittest_LDADD = $(LIBTCMALLOC_MINIMAL) $(PTHREAD_LIBS)
# This tests it works to LD_PRELOAD libtcmalloc (tests maybe_threads.cc)
# In theory this should work under mingw, but mingw has trouble running
# shell scripts that end in .exe. And it doesn't seem to build shared
# libraries anyway (so can't be LD_PRELOADed) -- in fact, anybody who
# chooses not to build shared libraries won't be able to run this test.
# TODO(csilvers): figure out how to nix ".exe" or otherwise work under mingw
if !MINGW
if !ENABLE_STATIC
TESTS += maybe_threads_unittest.sh$(EXEEXT)
maybe_threads_unittest_sh_SOURCES = src/tests/maybe_threads_unittest.sh
noinst_SCRIPTS += $(maybe_threads_unittest_sh_SOURCES)
# This script preloads libtcmalloc, and calls two other binaries as well
# TODO(csilvers): replace by 'if ! cmp $^ $@ >/dev/null 2>&; then ...; fi'
maybe_threads_unittest.sh$(EXEEXT): $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) \
$(LIBTCMALLOC_MINIMAL) \
low_level_alloc_unittest
rm -f $@
cp -p $(top_srcdir)/$(maybe_threads_unittest_sh_SOURCES) $@
endif !ENABLE_STATIC
endif !MINGW
# These all tests components of tcmalloc_minimal
TESTS += addressmap_unittest
@ -934,7 +902,7 @@ libtcmalloc_la_SOURCES = $(TCMALLOC_CC) $(TCMALLOC_INCLUDES) \
libtcmalloc_la_CXXFLAGS = $(PTHREAD_CFLAGS) -DNDEBUG $(AM_CXXFLAGS) \
$(MAYBE_NO_HEAP_CHECK) $(EMERGENCY_MALLOC_DEFINE)
libtcmalloc_la_LDFLAGS = $(PTHREAD_CFLAGS) -version-info @TCMALLOC_SO_VERSION@
libtcmalloc_la_LIBADD = libtcmalloc_internal.la libmaybe_threads.la $(PTHREAD_LIBS)
libtcmalloc_la_LIBADD = libtcmalloc_internal.la $(PTHREAD_LIBS)
# same as above with without -DNDEBUG
noinst_LTLIBRARIES += libtcmalloc_internal_with_asserts.la
@ -950,7 +918,7 @@ libtcmalloc_with_asserts_la_SOURCES = $(libtcmalloc_la_SOURCES)
libtcmalloc_with_asserts_la_CXXFLAGS = $(PTHREAD_CFLAGS) $(AM_CXXFLAGS) \
$(MAYBE_NO_HEAP_CHECK) $(EMERGENCY_MALLOC_DEFINE)
libtcmalloc_with_asserts_la_LDFLAGS = $(PTHREAD_CFLAGS)
libtcmalloc_with_asserts_la_LIBADD = libtcmalloc_internal_with_asserts.la libmaybe_threads.la $(PTHREAD_LIBS)
libtcmalloc_with_asserts_la_LIBADD = libtcmalloc_internal_with_asserts.la $(PTHREAD_LIBS)
LIBTCMALLOC = libtcmalloc.la
@ -1270,7 +1238,7 @@ libprofiler_la_SOURCES = src/profiler.cc \
src/profile-handler.cc \
src/profiledata.cc \
$(CPU_PROFILER_INCLUDES)
libprofiler_la_LIBADD = libstacktrace.la libmaybe_threads.la libfake_stacktrace_scope.la
libprofiler_la_LIBADD = libstacktrace.la libfake_stacktrace_scope.la
# We have to include ProfileData for profiledata_unittest
CPU_PROFILER_SYMBOLS = '(ProfilerStart|ProfilerStartWithOptions|ProfilerStop|ProfilerFlush|ProfilerEnable|ProfilerDisable|ProfilingIsEnabledForAllThreads|ProfilerRegisterThread|ProfilerGetCurrentState|ProfilerState|ProfileData|ProfileHandler|ProfilerGetStackTrace)'
libprofiler_la_LDFLAGS = -export-symbols-regex $(CPU_PROFILER_SYMBOLS) \

View File

@ -518,23 +518,6 @@ AC_SUBST(LIBSTDCXX_LA_LINKER_FLAG)
# In fact, a lot of the code in this directory depends on pthreads
AX_PTHREAD
AC_MSG_CHECKING([whether pthread symbols are available in C++ without including pthread.h])
acx_pthread_despite_asking_for=no
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([
#include <string>
#include <vector>
],[
pthread_t th; pthread_join(th, 0);
])],[
acx_pthread_despite_asking_for=yes
AC_DEFINE(HAVE_PTHREAD_DESPITE_ASKING_FOR, 1, [defined to 1 if pthread symbols are exposed even without include pthread.h])
AC_DEFINE(HAVE_PTHREAD, 1, [])
])
AC_MSG_RESULT([$acx_pthread_despite_asking_for])
AM_CONDITIONAL(HAVE_PTHREAD_DESPITE_ASKING_FOR, test x"$acx_pthread_despite_asking_for" = xyes)
# Figure out where libc has program_invocation_name
AC_PROGRAM_INVOCATION_NAME

View File

@ -84,7 +84,6 @@
#include "base/sysinfo.h"
#include "heap-profile-table.h"
#include "malloc_hook-inl.h"
#include "maybe_threads.h"
#include "memory_region_map.h"
#include "safe_strerror.h"
@ -555,7 +554,7 @@ inline void set_thread_disable_counter(int value) {
class InitThreadDisableCounter {
public:
InitThreadDisableCounter() {
perftools_pthread_key_create(&thread_disable_counter_key, NULL);
pthread_key_create(&thread_disable_counter_key, NULL);
// Set up the main thread's value, which we have a special variable for.
void* p = (void*)(intptr_t)main_thread_counter; // store the counter directly
perftools_pthread_setspecific(thread_disable_counter_key, p);

View File

@ -50,7 +50,6 @@
#endif
#include "gperftools/malloc_extension.h"
#include "gperftools/malloc_extension_c.h"
#include "maybe_threads.h"
#include "base/googleinit.h"
using std::string;

View File

@ -50,7 +50,6 @@
#include "base/logging.h"
#include "base/spinlock.h"
#include "maybe_emergency_malloc.h"
#include "maybe_threads.h"
#include "malloc_hook-inl.h"
#include <gperftools/malloc_hook.h>

View File

@ -1,144 +0,0 @@
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
// Author: Paul Menage <opensource@google.com>
//
// Some wrappers for pthread functions so that we can be LD_PRELOADed
// against non-pthreads apps.
//
// This module will behave very strangely if some pthreads functions
// exist and others don't.
#include "config.h"
#include <assert.h>
#include <string.h> // for memcmp
#include <stdio.h> // for __isthreaded on FreeBSD
// We don't actually need strings. But including this header seems to
// stop the compiler trying to short-circuit our pthreads existence
// tests and claiming that the address of a function is always
// non-zero. I have no idea why ...
#include <string>
#include "maybe_threads.h"
#include "base/basictypes.h"
#include "base/logging.h"
// __THROW is defined in glibc systems. It means, counter-intuitively,
// "This function will never throw an exception." It's an optional
// optimization tool, but we may need to use it to match glibc prototypes.
#ifndef __THROW // I guess we're not on a glibc system
# define __THROW // __THROW is just an optimization, so ok to make it ""
#endif
// These are the methods we're going to conditionally include.
extern "C" {
int pthread_key_create (pthread_key_t*, void (*)(void*))
__THROW ATTRIBUTE_WEAK;
int pthread_key_delete (pthread_key_t)
__THROW ATTRIBUTE_WEAK;
void *pthread_getspecific(pthread_key_t)
__THROW ATTRIBUTE_WEAK;
int pthread_setspecific(pthread_key_t, const void*)
__THROW ATTRIBUTE_WEAK;
int pthread_once(pthread_once_t *, void (*)(void))
ATTRIBUTE_WEAK;
#ifdef HAVE_FORK
int pthread_atfork(void (*__prepare) (void),
void (*__parent) (void),
void (*__child) (void))
__THROW ATTRIBUTE_WEAK;
#endif
}
#define MAX_PERTHREAD_VALS 16
static void *perftools_pthread_specific_vals[MAX_PERTHREAD_VALS];
static int next_key;
// NOTE: it's similar to bitcast defined in basic_types.h with
// exception of ignoring sizes mismatch
template <typename T1, typename T2>
static T2 memcpy_cast(const T1 &input) {
T2 output;
size_t s = sizeof(input);
if (sizeof(output) < s) {
s = sizeof(output);
}
memcpy(&output, &input, s);
return output;
}
int perftools_pthread_key_create(pthread_key_t *key,
void (*destr_function) (void *)) {
if (pthread_key_create) {
return pthread_key_create(key, destr_function);
} else {
assert(next_key < MAX_PERTHREAD_VALS);
*key = memcpy_cast<int, pthread_key_t>(next_key++);
return 0;
}
}
int perftools_pthread_key_delete(pthread_key_t key) {
if (pthread_key_delete) {
return pthread_key_delete(key);
} else {
return 0;
}
}
void *perftools_pthread_getspecific(pthread_key_t key) {
if (pthread_getspecific) {
return pthread_getspecific(key);
} else {
return perftools_pthread_specific_vals[memcpy_cast<pthread_key_t, int>(key)];
}
}
int perftools_pthread_setspecific(pthread_key_t key, void *val) {
if (pthread_setspecific) {
return pthread_setspecific(key, val);
} else {
perftools_pthread_specific_vals[memcpy_cast<pthread_key_t, int>(key)] = val;
return 0;
}
}
#ifdef HAVE_FORK
void perftools_pthread_atfork(void (*before)(),
void (*parent_after)(),
void (*child_after)()) {
if (pthread_atfork) {
int rv = pthread_atfork(before, parent_after, child_after);
CHECK(rv == 0);
}
}
#endif

View File

@ -1,59 +0,0 @@
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
// Copyright (c) 2005, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
// Author: Paul Menage <opensource@google.com>
//-------------------------------------------------------------------
// Some wrappers for pthread functions so that we can be LD_PRELOADed
// against non-pthreads apps.
//-------------------------------------------------------------------
#ifndef GOOGLE_MAYBE_THREADS_H_
#define GOOGLE_MAYBE_THREADS_H_
#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif
int perftools_pthread_key_create(pthread_key_t *key,
void (*destr_function) (void *));
int perftools_pthread_key_delete(pthread_key_t key);
void *perftools_pthread_getspecific(pthread_key_t key);
int perftools_pthread_setspecific(pthread_key_t key, void *val);
// Our wrapper for pthread_atfork. Does _nothing_ when there are no
// threads. See static_vars.cc:SetupAtForkLocksHandler for only user
// of this.
void perftools_pthread_atfork(void (*before)(),
void (*parent_after)(),
void (*child_after)());
#endif /* GOOGLE_MAYBE_THREADS_H_ */

View File

@ -47,22 +47,19 @@
#include <string>
#if HAVE_LINUX_SIGEV_THREAD_ID
#include <pthread.h>
// for timer_{create,settime} and associated typedefs & constants
#include <time.h>
// for sigevent
#include <signal.h>
// for SYS_gettid
#include <sys/syscall.h>
// for perftools_pthread_key_create
#include "maybe_threads.h"
#endif
#include "base/dynamic_annotations.h"
#include "base/googleinit.h"
#include "base/logging.h"
#include "base/spinlock.h"
#include "maybe_threads.h"
// Some Linux systems don't have sigev_notify_thread_id defined in
// signal.h (despite having SIGEV_THREAD_ID defined) and also lack
@ -268,7 +265,7 @@ extern "C" {
}
static void CreateThreadTimerKey(pthread_key_t *pkey) {
int rv = perftools_pthread_key_create(pkey, ThreadTimerDestructor);
int rv = pthread_key_create(pkey, ThreadTimerDestructor);
if (rv) {
RAW_LOG(FATAL, "aborting due to pthread_key_create error: %s", strerror(rv));
}
@ -294,7 +291,7 @@ static void StartLinuxThreadTimer(int timer_type, int signal_number,
}
timer_id_holder *holder = new timer_id_holder(timerid);
rv = perftools_pthread_setspecific(timer_key, holder);
rv = pthread_setspecific(timer_key, holder);
if (rv) {
RAW_LOG(FATAL, "aborting due to pthread_setspecific error: %s", strerror(rv));
}
@ -393,7 +390,7 @@ ProfileHandler::~ProfileHandler() {
Reset();
#ifdef HAVE_LINUX_SIGEV_THREAD_ID
if (per_thread_timer_enabled_) {
perftools_pthread_key_delete(thread_timer_key);
pthread_key_delete(thread_timer_key);
}
#endif
}

View File

@ -43,7 +43,6 @@
#include "sampler.h" // for Sampler
#include "getenv_safe.h" // TCMallocGetenvSafe
#include "base/googleinit.h"
#include "maybe_threads.h"
namespace tcmalloc {
@ -137,7 +136,7 @@ void Static::InitLateMaybeRecursive() {
// be less fortunate and allow some early app constructors to run
// before malloc is ever called.
perftools_pthread_atfork(
pthread_atfork(
CentralCacheLockAll, // parent calls before fork
CentralCacheUnlockAll, // parent calls after fork
CentralCacheUnlockAll); // child calls after fork

View File

@ -163,8 +163,6 @@ static void FreeHook(const void *p) {
}
int main(int argc, char *argv[]) {
// This is needed by maybe_threads_unittest.sh, which parses argv[0]
// to figure out what directory low_level_alloc_unittest is in.
if (argc != 1) {
fprintf(stderr, "USAGE: %s\n", argv[0]);
return 1;

View File

@ -1,79 +0,0 @@
#!/bin/sh
# Copyright (c) 2007, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# ---
# Author: Craig Silverstein
#
# maybe_threads.cc was written to allow LD_PRELOAD=libtcmalloc.so to
# work even on binaries that were not linked with pthreads. This
# unittest tests that, by running low_level_alloc_unittest with an
# LD_PRELOAD. (low_level_alloc_unittest was chosen because it doesn't
# link in tcmalloc.)
#
# We assume all the .so files are in the same directory as both
# addressmap_unittest and profiler1_unittest. The reason we need
# profiler1_unittest is because it's instrumented to show the directory
# it's "really" in when run without any args. In practice this will either
# be BINDIR, or, when using libtool, BINDIR/.lib.
# We expect BINDIR to be set in the environment.
# If not, we set them to some reasonable values.
BINDIR="${BINDIR:-.}"
if [ "x$1" = "x-h" -o "x$1" = "x--help" ]; then
echo "USAGE: $0 [unittest dir]"
echo " By default, unittest_dir=$BINDIR"
exit 1
fi
UNITTEST_DIR=${1:-$BINDIR}
# Figure out the "real" unittest directory. Also holds the .so files.
UNITTEST_DIR=`$UNITTEST_DIR/low_level_alloc_unittest --help 2>&1 \
| awk '{print $2; exit;}' \
| xargs dirname`
# Figure out where libtcmalloc lives. It should be in UNITTEST_DIR,
# but with libtool it might be in a subdir.
if [ -r "$UNITTEST_DIR/libtcmalloc_minimal.so" ]; then
LIB_PATH="$UNITTEST_DIR/libtcmalloc_minimal.so"
elif [ -r "$UNITTEST_DIR/.libs/libtcmalloc_minimal.so" ]; then
LIB_PATH="$UNITTEST_DIR/.libs/libtcmalloc_minimal.so"
elif [ -r "$UNITTEST_DIR/libtcmalloc_minimal.dylib" ]; then # for os x
LIB_PATH="$UNITTEST_DIR/libtcmalloc_minimal.dylib"
elif [ -r "$UNITTEST_DIR/.libs/libtcmalloc_minimal.dylib" ]; then
LIB_PATH="$UNITTEST_DIR/.libs/libtcmalloc_minimal.dylib"
else
echo "Cannot run $0: cannot find libtcmalloc_minimal.so"
exit 2
fi
LD_PRELOAD="$LIB_PATH" $UNITTEST_DIR/low_level_alloc_unittest

View File

@ -40,7 +40,6 @@
#include "base/spinlock.h" // for SpinLockHolder
#include "getenv_safe.h" // for TCMallocGetenvSafe
#include "central_freelist.h" // for CentralFreeListPadded
#include "maybe_threads.h"
using std::min;
using std::max;

View File

@ -46,7 +46,6 @@
#include "base/commandlineflags.h"
#include "common.h"
#include "linked_list.h"
#include "maybe_threads.h"
#include "page_heap_allocator.h"
#include "sampler.h"
#include "static_vars.h"
@ -60,6 +59,12 @@
DECLARE_int64(tcmalloc_sample_parameter);
#ifndef HAVE_PERFTOOLS_PTHREAD_KEYS
#define perftools_pthread_getspecific pthread_getspecific
#define perftools_pthread_setspecific pthread_setspecific
#define perftools_pthread_key_create pthread_key_create
#endif
namespace tcmalloc {
//-------------------------------------------------------------------

View File

@ -130,8 +130,7 @@ inline bool pthread_equal(pthread_t left, pthread_t right) {
* we therefore shouldn't be #including directly. This hack keeps us from
* doing so. TODO(csilvers): do something more principled.
*/
#define GOOGLE_MAYBE_THREADS_H_ 1
/* This replaces maybe_threads.{h,cc} */
#define HAVE_PERFTOOLS_PTHREAD_KEYS
EXTERN_C pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)); /* port.cc */