mirror of
https://github.com/gperftools/gperftools
synced 2025-02-17 12:46:51 +00:00
Convert MinGW builds to always use WinAPI based threading facilities. See ##1483
This commit is contained in:
parent
e3b3a77727
commit
5cab8f3f77
@ -553,6 +553,7 @@ set(LOGGING_INCLUDES
|
||||
src/base/logging.h
|
||||
src/base/commandlineflags.h
|
||||
src/base/basictypes.h
|
||||
src/base/threading.h
|
||||
src/base/dynamic_annotations.h)
|
||||
set(liblogging_la_SOURCES src/base/logging.cc
|
||||
src/base/generic_writer.cc
|
||||
@ -565,6 +566,7 @@ set(SYSINFO_INCLUDES
|
||||
src/getenv_safe.h
|
||||
src/base/logging.h
|
||||
src/base/commandlineflags.h
|
||||
src/base/threading.h
|
||||
src/base/basictypes.h)
|
||||
set(libsysinfo_la_SOURCES src/base/sysinfo.cc
|
||||
${SYSINFO_INCLUDES})
|
||||
@ -634,6 +636,7 @@ endif()
|
||||
if(BUILD_TESTING)
|
||||
set(LOW_LEVEL_ALLOC_UNITTEST_INCLUDES
|
||||
src/base/low_level_alloc.h
|
||||
src/base/threading.h
|
||||
src/base/basictypes.h
|
||||
src/gperftools/malloc_hook.h
|
||||
src/gperftools/malloc_hook_c.h
|
||||
@ -735,6 +738,7 @@ set(S_TCMALLOC_MINIMAL_INCLUDES src/common.h
|
||||
${SPINLOCK_INCLUDES}
|
||||
src/tcmalloc_guard.h
|
||||
src/base/commandlineflags.h
|
||||
src/base/threading.h
|
||||
src/base/basictypes.h
|
||||
src/safe_strerror.h
|
||||
src/pagemap.h
|
||||
@ -1322,6 +1326,7 @@ if(GPERFTOOLS_BUILD_CPU_PROFILER)
|
||||
set(S_CPU_PROFILER_INCLUDES src/profiledata.h
|
||||
src/profile-handler.h
|
||||
src/getpc.h
|
||||
src/base/threading.h
|
||||
src/base/basictypes.h
|
||||
src/base/commandlineflags.h
|
||||
src/base/googleinit.h
|
||||
@ -1369,6 +1374,7 @@ if(GPERFTOOLS_BUILD_CPU_PROFILER)
|
||||
src/profiledata.h
|
||||
src/base/commandlineflags.h
|
||||
src/base/logging.h
|
||||
src/base/threading.h
|
||||
src/base/basictypes.h)
|
||||
target_link_libraries(profiledata_unittest ${LIBPROFILER})
|
||||
add_test(profiledata_unittest profiledata_unittest)
|
||||
|
@ -154,6 +154,7 @@ dist_doc_DATA += docs/index.html docs/designstyle.css
|
||||
# This is a 'convenience library' -- it's not actually installed or anything
|
||||
LOGGING_INCLUDES = src/base/logging.h \
|
||||
src/base/commandlineflags.h \
|
||||
src/base/threading.h \
|
||||
src/base/basictypes.h \
|
||||
src/base/generic_writer.h \
|
||||
src/base/dynamic_annotations.h
|
||||
@ -166,6 +167,7 @@ SYSINFO_INCLUDES = src/base/sysinfo.h \
|
||||
src/getenv_safe.h \
|
||||
src/base/logging.h \
|
||||
src/base/commandlineflags.h \
|
||||
src/base/threading.h \
|
||||
src/base/basictypes.h
|
||||
noinst_LTLIBRARIES += libsysinfo.la
|
||||
libsysinfo_la_SOURCES = src/base/sysinfo.cc \
|
||||
@ -262,6 +264,7 @@ WINDOWS_PROJECTS += vsprojects/low_level_alloc_unittest/low_level_alloc_unittest
|
||||
TESTS += low_level_alloc_unittest
|
||||
LOW_LEVEL_ALLOC_UNITTEST_INCLUDES = src/base/low_level_alloc.h \
|
||||
src/base/basictypes.h \
|
||||
src/base/threading.h \
|
||||
src/gperftools/malloc_hook.h \
|
||||
src/gperftools/malloc_hook_c.h \
|
||||
src/malloc_hook-inl.h \
|
||||
@ -386,6 +389,7 @@ S_TCMALLOC_MINIMAL_INCLUDES = src/common.h \
|
||||
$(SPINLOCK_INCLUDES) \
|
||||
src/tcmalloc_guard.h \
|
||||
src/base/commandlineflags.h \
|
||||
src/base/threading.h \
|
||||
src/base/basictypes.h \
|
||||
src/safe_strerror.h \
|
||||
src/pagemap.h \
|
||||
@ -1246,6 +1250,7 @@ S_CPU_PROFILER_INCLUDES = src/profiledata.h \
|
||||
src/getpc.h \
|
||||
src/getpc-inl.h \
|
||||
src/base/basictypes.h \
|
||||
src/base/threading.h \
|
||||
src/base/commandlineflags.h \
|
||||
src/base/googleinit.h \
|
||||
src/base/logging.h \
|
||||
@ -1283,6 +1288,7 @@ profiledata_unittest_SOURCES = src/tests/profiledata_unittest.cc \
|
||||
src/profiledata.h \
|
||||
src/base/commandlineflags.h \
|
||||
src/base/logging.h \
|
||||
src/base/threading.h \
|
||||
src/base/basictypes.h
|
||||
profiledata_unittest_LDADD = libprofiler.la
|
||||
|
||||
|
@ -112,10 +112,6 @@
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#cmakedefine HAVE_PTHREAD
|
||||
|
||||
/* defined to 1 if pthread symbols are exposed even without include pthread.h
|
||||
*/
|
||||
#cmakedefine HAVE_PTHREAD_DESPITE_ASKING_FOR
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#cmakedefine HAVE_PWD_H
|
||||
|
||||
|
@ -101,17 +101,6 @@ const int64 kint64min = ( (((uint64) kint32min) << 32) | 0 );
|
||||
#define PRIxPTR "lx"
|
||||
#endif
|
||||
|
||||
// Also allow for printing of a pthread_t.
|
||||
#define GPRIuPTHREAD "lu"
|
||||
#define GPRIxPTHREAD "lx"
|
||||
#if defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#define PRINTABLE_PTHREAD(pthreadt) reinterpret_cast<uintptr_t>(pthreadt)
|
||||
#elif defined(__QNXNTO__)
|
||||
#define PRINTABLE_PTHREAD(pthreadt) static_cast<intptr_t>(pthreadt)
|
||||
#else
|
||||
#define PRINTABLE_PTHREAD(pthreadt) pthreadt
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define PREDICT_TRUE(x) __builtin_expect(!!(x), 1)
|
||||
#define PREDICT_FALSE(x) __builtin_expect(!!(x), 0)
|
||||
|
127
src/base/threading.h
Normal file
127
src/base/threading.h
Normal file
@ -0,0 +1,127 @@
|
||||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2024, gperftools Contributors
|
||||
// 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.
|
||||
|
||||
#ifndef THREADING_H_
|
||||
#define THREADING_H_
|
||||
|
||||
#include <config.h>
|
||||
#include "base/basictypes.h"
|
||||
|
||||
// Also allow for printing of a PerftoolsThreadID.
|
||||
#define GPRIuPTHREAD "lu"
|
||||
#define GPRIxPTHREAD "lx"
|
||||
|
||||
#if defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__APPLE__) || defined(__FreeBSD__)
|
||||
# define PRINTABLE_PTHREAD(pthreadt) reinterpret_cast<uintptr_t>(pthreadt)
|
||||
#elif defined(__QNXNTO__)
|
||||
# define PRINTABLE_PTHREAD(pthreadt) static_cast<intptr_t>(pthreadt)
|
||||
#else
|
||||
# define PRINTABLE_PTHREAD(pthreadt) pthreadt
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32 // Should cover both toolchains on Windows - MSVC & MINGW
|
||||
|
||||
using PerftoolsThreadID = DWORD;
|
||||
using PerftoolsTlsKey = DWORD;
|
||||
|
||||
inline PerftoolsThreadID PerftoolsGetThreadID() {
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
inline int PerftoolsThreadIDEquals(PerftoolsThreadID left, PerftoolsThreadID right) {
|
||||
return left == right;
|
||||
}
|
||||
|
||||
extern "C" PerftoolsTlsKey PthreadKeyCreate(void (*destr_fn)(void*)); /* port.cc */
|
||||
|
||||
inline int PerftoolsCreateTlsKey(PerftoolsTlsKey *pkey, void (*destructor)(void*)) {
|
||||
PerftoolsTlsKey key = PthreadKeyCreate(destructor);
|
||||
|
||||
if (key != TLS_OUT_OF_INDEXES) {
|
||||
*(pkey) = key;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
inline void* PerftoolsGetTlsValue(PerftoolsTlsKey key) {
|
||||
DWORD err = GetLastError();
|
||||
void* rv = TlsGetValue(key);
|
||||
|
||||
if (err) SetLastError(err);
|
||||
return rv;
|
||||
}
|
||||
inline int PerftoolsSetTlsValue(PerftoolsTlsKey key, const void* value) {
|
||||
if (TlsSetValue(key, (LPVOID)value)) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
inline void PerftoolsYield() {
|
||||
Sleep(0);
|
||||
}
|
||||
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
|
||||
# include <pthread.h>
|
||||
# include <sched.h>
|
||||
|
||||
using PerftoolsThreadID = pthread_t;
|
||||
using PerftoolsTlsKey = pthread_key_t;
|
||||
|
||||
inline PerftoolsThreadID PerftoolsGetThreadID() {
|
||||
return pthread_self();
|
||||
}
|
||||
inline int PerftoolsThreadIDEquals(PerftoolsThreadID left, PerftoolsThreadID right) {
|
||||
return pthread_equal(left, right);
|
||||
}
|
||||
|
||||
inline int PerftoolsCreateTlsKey(PerftoolsTlsKey *pkey, void (*destructor)(void*)) {
|
||||
return pthread_key_create(pkey, destructor);
|
||||
}
|
||||
inline void* PerftoolsGetTlsValue(PerftoolsTlsKey key) {
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
inline int PerftoolsSetTlsValue(PerftoolsTlsKey key, const void* value) {
|
||||
return pthread_setspecific(key, value);
|
||||
}
|
||||
|
||||
inline ATTRIBUTE_ALWAYS_INLINE void PerftoolsYield() {
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
#else
|
||||
# error "Threading support is now mandatory"
|
||||
#endif
|
||||
|
||||
#endif // THREADING_H_
|
@ -48,9 +48,6 @@
|
||||
# include <sys/malloc.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_PTHREAD
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -69,6 +66,7 @@
|
||||
|
||||
#include "addressmap-inl.h"
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/threading.h"
|
||||
#include "base/googleinit.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/spinlock.h"
|
||||
@ -206,7 +204,7 @@ struct MallocBlockQueueEntry {
|
||||
deleter_pcs,
|
||||
sizeof(deleter_pcs) / sizeof(deleter_pcs[0]),
|
||||
4);
|
||||
deleter_threadid = pthread_self();
|
||||
deleter_threadid = PerftoolsGetThreadID();
|
||||
} else {
|
||||
num_deleter_pcs = 0;
|
||||
// Zero is an illegal pthread id by my reading of the pthread
|
||||
@ -224,7 +222,7 @@ struct MallocBlockQueueEntry {
|
||||
// overhead under the LP64 data model.)
|
||||
void* deleter_pcs[16];
|
||||
int num_deleter_pcs;
|
||||
pthread_t deleter_threadid;
|
||||
PerftoolsThreadID deleter_threadid;
|
||||
};
|
||||
|
||||
class MallocBlock {
|
||||
@ -1009,7 +1007,7 @@ static SpinLock malloc_trace_lock(SpinLock::LINKER_INITIALIZED);
|
||||
if (FLAGS_malloctrace) { \
|
||||
SpinLockHolder l(&malloc_trace_lock); \
|
||||
TracePrintf(TraceFd(), "%s\t%zu\t%p\t%" GPRIuPTHREAD, \
|
||||
name, size, addr, PRINTABLE_PTHREAD(pthread_self())); \
|
||||
name, size, addr, PRINTABLE_PTHREAD(PerftoolsGetThreadID())); \
|
||||
TraceStack(); \
|
||||
TracePrintf(TraceFd(), "\n"); \
|
||||
} \
|
||||
|
@ -530,17 +530,17 @@ inline void set_thread_disable_counter(int value) {
|
||||
|
||||
#else // #ifdef HAVE_TLS
|
||||
|
||||
static pthread_key_t thread_disable_counter_key;
|
||||
static PerftoolsTlsKey thread_disable_counter_key;
|
||||
static int main_thread_counter; // storage for use before main()
|
||||
static bool use_main_thread_counter = true;
|
||||
|
||||
// TODO(csilvers): this is called from NewHook, in the middle of malloc().
|
||||
// If perftools_pthread_getspecific calls malloc, that will lead to an
|
||||
// If PerftoolsGetTlsValue calls malloc, that will lead to an
|
||||
// infinite loop. I don't know how to fix that, so I hope it never happens!
|
||||
inline int get_thread_disable_counter() {
|
||||
if (use_main_thread_counter) // means we're running really early
|
||||
return main_thread_counter;
|
||||
void* p = perftools_pthread_getspecific(thread_disable_counter_key);
|
||||
void* p = PerftoolsGetTlsValue(thread_disable_counter_key);
|
||||
return (intptr_t)p; // kinda evil: store the counter directly in the void*
|
||||
}
|
||||
|
||||
@ -553,10 +553,10 @@ inline void set_thread_disable_counter(int value) {
|
||||
// kinda evil: store the counter directly in the void*
|
||||
void* p = (void*)pointer_sized_value;
|
||||
// NOTE: this may call malloc, which will call NewHook which will call
|
||||
// get_thread_disable_counter() which will call pthread_getspecific(). I
|
||||
// get_thread_disable_counter() which will call PerftoolsGetTlsValue(). I
|
||||
// don't know if anything bad can happen if we call getspecific() in the
|
||||
// middle of a setspecific() call. It seems to work ok in practice...
|
||||
perftools_pthread_setspecific(thread_disable_counter_key, p);
|
||||
PerftoolsSetTlsValue(thread_disable_counter_key, p);
|
||||
}
|
||||
|
||||
// The idea here is that this initializer will run pretty late: after
|
||||
@ -565,10 +565,10 @@ inline void set_thread_disable_counter(int value) {
|
||||
class InitThreadDisableCounter {
|
||||
public:
|
||||
InitThreadDisableCounter() {
|
||||
pthread_key_create(&thread_disable_counter_key, NULL);
|
||||
PerftoolsCreateTlsKey(&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);
|
||||
PerftoolsSetTlsValue(thread_disable_counter_key, p);
|
||||
use_main_thread_counter = false;
|
||||
}
|
||||
};
|
||||
@ -906,7 +906,7 @@ void HeapLeakChecker::DisableLibraryAllocsLocked(const char* library,
|
||||
if (IsLibraryNamed(library, "/libpthread") ||
|
||||
// libpthread has a lot of small "system" leaks we don't care about.
|
||||
// In particular it allocates memory to store data supplied via
|
||||
// pthread_setspecific (which can be the only pointer to a heap object).
|
||||
// PerftoolsSetTlsValue (which can be the only pointer to a heap object).
|
||||
IsLibraryNamed(library, "/libdl") ||
|
||||
// library loaders leak some "system" heap that we don't care about
|
||||
IsLibraryNamed(library, "/libcrypto") ||
|
||||
|
@ -108,9 +108,6 @@
|
||||
#elif !defined(MAP_FAILED)
|
||||
#define MAP_FAILED -1 // the only thing we need from mman.h
|
||||
#endif
|
||||
#ifdef HAVE_PTHREAD
|
||||
#include <pthread.h> // for pthread_t, pthread_self()
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
|
||||
#include <algorithm>
|
||||
@ -121,6 +118,7 @@
|
||||
#include "base/googleinit.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/low_level_alloc.h"
|
||||
#include "base/threading.h"
|
||||
#include "mmap_hook.h"
|
||||
|
||||
#include <gperftools/stacktrace.h>
|
||||
@ -138,7 +136,7 @@ SpinLock MemoryRegionMap::lock_(SpinLock::LINKER_INITIALIZED);
|
||||
SpinLock MemoryRegionMap::owner_lock_( // ACQUIRED_AFTER(lock_)
|
||||
SpinLock::LINKER_INITIALIZED);
|
||||
int MemoryRegionMap::recursion_count_ = 0; // GUARDED_BY(owner_lock_)
|
||||
pthread_t MemoryRegionMap::lock_owner_tid_; // GUARDED_BY(owner_lock_)
|
||||
PerftoolsThreadID MemoryRegionMap::lock_owner_tid_; // GUARDED_BY(owner_lock_)
|
||||
int64 MemoryRegionMap::map_size_ = 0;
|
||||
int64 MemoryRegionMap::unmap_size_ = 0;
|
||||
HeapProfileBucket** MemoryRegionMap::bucket_table_ = NULL; // GUARDED_BY(lock_)
|
||||
@ -152,16 +150,16 @@ tcmalloc::MappingHookSpace MemoryRegionMap::mapping_hook_space_;
|
||||
// ========================================================================= //
|
||||
|
||||
// Simple hook into execution of global object constructors,
|
||||
// so that we do not call pthread_self() when it does not yet work.
|
||||
// so that we do not call PerftoolsGetThreadID() when it does not yet work.
|
||||
static bool libpthread_initialized = false;
|
||||
REGISTER_MODULE_INITIALIZER(libpthread_initialized_setter,
|
||||
libpthread_initialized = true);
|
||||
|
||||
static inline bool current_thread_is(pthread_t should_be) {
|
||||
static inline bool current_thread_is(PerftoolsThreadID should_be) {
|
||||
// Before main() runs, there's only one thread, so we're always that thread
|
||||
if (!libpthread_initialized) return true;
|
||||
// this starts working only sometime well into global constructor execution:
|
||||
return pthread_equal(pthread_self(), should_be);
|
||||
return PerftoolsThreadIDEquals(PerftoolsGetThreadID(), should_be);
|
||||
}
|
||||
|
||||
// ========================================================================= //
|
||||
@ -283,7 +281,7 @@ bool MemoryRegionMap::IsRecordingLocked() {
|
||||
// both lock_ and owner_lock_ are held. They may be read under
|
||||
// just owner_lock_.
|
||||
// * At entry and exit of Lock() and Unlock(), the current thread
|
||||
// owns lock_ iff pthread_equal(lock_owner_tid_, pthread_self())
|
||||
// owns lock_ iff PerftoolsThreadIDEquals(lock_owner_tid_, PerftoolsGetThreadID())
|
||||
// && recursion_count_ > 0.
|
||||
void MemoryRegionMap::Lock() NO_THREAD_SAFETY_ANALYSIS {
|
||||
{
|
||||
@ -302,7 +300,7 @@ void MemoryRegionMap::Lock() NO_THREAD_SAFETY_ANALYSIS {
|
||||
RAW_CHECK(recursion_count_ == 0,
|
||||
"Last Unlock didn't reset recursion_count_");
|
||||
if (libpthread_initialized)
|
||||
lock_owner_tid_ = pthread_self();
|
||||
lock_owner_tid_ = PerftoolsGetThreadID();
|
||||
recursion_count_ = 1;
|
||||
}
|
||||
}
|
||||
|
@ -37,13 +37,11 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef HAVE_PTHREAD
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
#include <set>
|
||||
#include "base/stl_allocator.h"
|
||||
#include "base/spinlock.h"
|
||||
#include "base/threading.h"
|
||||
#include "base/thread_annotations.h"
|
||||
#include "base/low_level_alloc.h"
|
||||
#include "heap-profile-stats.h"
|
||||
@ -310,7 +308,7 @@ class MemoryRegionMap {
|
||||
// Recursion count for the recursive lock.
|
||||
static int recursion_count_;
|
||||
// The thread id of the thread that's inside the recursive lock.
|
||||
static pthread_t lock_owner_tid_;
|
||||
static PerftoolsThreadID lock_owner_tid_;
|
||||
|
||||
// Total size of all mapped pages so far
|
||||
static int64 map_size_;
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include "base/googleinit.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/spinlock.h"
|
||||
#include "base/threading.h"
|
||||
|
||||
// Some Linux systems don't have sigev_notify_thread_id defined in
|
||||
// signal.h (despite having SIGEV_THREAD_ID defined) and also lack
|
||||
@ -181,7 +182,7 @@ class ProfileHandler {
|
||||
#if HAVE_LINUX_SIGEV_THREAD_ID
|
||||
// this is used to destroy per-thread profiling timers on thread
|
||||
// termination
|
||||
pthread_key_t thread_timer_key;
|
||||
PerftoolsTlsKey thread_timer_key;
|
||||
#endif
|
||||
|
||||
// This lock serializes the registration of threads and protects the
|
||||
@ -264,15 +265,15 @@ extern "C" {
|
||||
}
|
||||
}
|
||||
|
||||
static void CreateThreadTimerKey(pthread_key_t *pkey) {
|
||||
int rv = pthread_key_create(pkey, ThreadTimerDestructor);
|
||||
static void CreateThreadTimerKey(PerftoolsTlsKey *pkey) {
|
||||
int rv = PerftoolsCreateTlsKey(pkey, ThreadTimerDestructor);
|
||||
if (rv) {
|
||||
RAW_LOG(FATAL, "aborting due to pthread_key_create error: %s", strerror(rv));
|
||||
RAW_LOG(FATAL, "aborting due to PerftoolsCreateTlsKey error: %s", strerror(rv));
|
||||
}
|
||||
}
|
||||
|
||||
static void StartLinuxThreadTimer(int timer_type, int signal_number,
|
||||
int32 frequency, pthread_key_t timer_key) {
|
||||
int32 frequency, PerftoolsTlsKey timer_key) {
|
||||
int rv;
|
||||
struct sigevent sevp;
|
||||
timer_t timerid;
|
||||
@ -291,9 +292,9 @@ static void StartLinuxThreadTimer(int timer_type, int signal_number,
|
||||
}
|
||||
|
||||
timer_id_holder *holder = new timer_id_holder(timerid);
|
||||
rv = pthread_setspecific(timer_key, holder);
|
||||
rv = PerftoolsSetTlsValue(timer_key, holder);
|
||||
if (rv) {
|
||||
RAW_LOG(FATAL, "aborting due to pthread_setspecific error: %s", strerror(rv));
|
||||
RAW_LOG(FATAL, "aborting due to PerftoolsSetTlsValue error: %s", strerror(rv));
|
||||
}
|
||||
|
||||
its.it_interval.tv_sec = 0;
|
||||
|
@ -1101,7 +1101,7 @@ size_t TCMallocImplementation::GetEstimatedAllocatedSize(size_t size) {
|
||||
// runs before main(), and therefore we do not have a chance to become
|
||||
// multi-threaded before initialization. We also create the TSD key
|
||||
// here. Presumably by the time this constructor runs, glibc is in
|
||||
// good enough shape to handle pthread_key_create().
|
||||
// good enough shape to handle PerftoolsCreateTlsKey().
|
||||
//
|
||||
// The constructor also takes the opportunity to tell STL to use
|
||||
// tcmalloc. We want to do this early, before construct time, so
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "base/generic_writer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
#include <memory>
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/simple_mutex.h"
|
||||
#include "base/sysinfo.h"
|
||||
#include "base/threading.h"
|
||||
#include "tests/testutil.h"
|
||||
|
||||
// On systems (like freebsd) that don't define MAP_ANONYMOUS, use the old
|
||||
@ -200,7 +201,7 @@ void MultithreadedTestThread(TestHookList* list, int shift,
|
||||
const auto value = reinterpret_cast<MallocHook::NewHook>((i << shift) + thread_num);
|
||||
EXPECT_TRUE(list->Add(value));
|
||||
|
||||
sched_yield(); // Ensure some more interleaving.
|
||||
PerftoolsYield(); // Ensure some more interleaving.
|
||||
|
||||
MallocHook::NewHook values[kHookListMaxValues + 1];
|
||||
int num_values = list->Traverse(values, kHookListMaxValues + 1);
|
||||
@ -217,11 +218,11 @@ void MultithreadedTestThread(TestHookList* list, int shift,
|
||||
snprintf(buf, sizeof(buf), "[%d/%d; ", value_index, num_values);
|
||||
message += buf;
|
||||
|
||||
sched_yield();
|
||||
PerftoolsYield();
|
||||
|
||||
EXPECT_TRUE(list->Remove(value));
|
||||
|
||||
sched_yield();
|
||||
PerftoolsYield();
|
||||
|
||||
num_values = list->Traverse(values, kHookListMaxValues);
|
||||
for (value_index = 0;
|
||||
@ -234,7 +235,7 @@ void MultithreadedTestThread(TestHookList* list, int shift,
|
||||
snprintf(buf, sizeof(buf), "%d]", num_values);
|
||||
message += buf;
|
||||
|
||||
sched_yield();
|
||||
PerftoolsYield();
|
||||
}
|
||||
fprintf(stderr, "thread %d: %s\n", thread_num, message.c_str());
|
||||
}
|
||||
|
@ -72,9 +72,9 @@ __thread ThreadCache::ThreadLocalData ThreadCache::threadlocal_data_
|
||||
ATTR_INITIAL_EXEC CACHELINE_ALIGNED;
|
||||
#endif
|
||||
bool ThreadCache::tsd_inited_ = false;
|
||||
pthread_key_t ThreadCache::heap_key_;
|
||||
PerftoolsTlsKey ThreadCache::heap_key_;
|
||||
|
||||
void ThreadCache::Init(pthread_t tid) {
|
||||
void ThreadCache::Init(PerftoolsThreadID tid) {
|
||||
size_ = 0;
|
||||
|
||||
max_size_ = 0;
|
||||
@ -308,17 +308,17 @@ void ThreadCache::InitModule() {
|
||||
|
||||
void ThreadCache::InitTSD() {
|
||||
ASSERT(!tsd_inited_);
|
||||
perftools_pthread_key_create(&heap_key_, DestroyThreadCache);
|
||||
PerftoolsCreateTlsKey(&heap_key_, DestroyThreadCache);
|
||||
tsd_inited_ = true;
|
||||
|
||||
#ifdef PTHREADS_CRASHES_IF_RUN_TOO_EARLY
|
||||
// We may have used a fake pthread_t for the main thread. Fix it.
|
||||
pthread_t zero;
|
||||
// We may have used a fake PerftoolsThreadID for the main thread. Fix it.
|
||||
PerftoolsThreadID 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();
|
||||
h->tid_ = PerftoolsGetThreadID();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -343,11 +343,11 @@ ThreadCache* ThreadCache::CreateCacheIfNecessary() {
|
||||
if (tsd_inited_) {
|
||||
// In most common case we're avoiding expensive linear search
|
||||
// through all heaps (see below). Working TLS enables faster
|
||||
// protection from malloc recursion in pthread_setspecific
|
||||
// protection from malloc recursion in PerftoolsSetTlsValue
|
||||
seach_condition = false;
|
||||
|
||||
if (current_heap_ptr != NULL) {
|
||||
// we're being recursively called by pthread_setspecific below.
|
||||
// we're being recursively called by PerftoolsSetTlsValue below.
|
||||
return *current_heap_ptr;
|
||||
}
|
||||
current_heap_ptr = &heap;
|
||||
@ -357,24 +357,24 @@ ThreadCache* ThreadCache::CreateCacheIfNecessary() {
|
||||
{
|
||||
SpinLockHolder h(Static::pageheap_lock());
|
||||
// On some old glibc's, and on freebsd's libc (as of freebsd 8.1),
|
||||
// calling pthread routines (even pthread_self) too early could
|
||||
// calling pthread routines (even PerftoolsGetThreadID) too early could
|
||||
// cause a segfault. Since we can call pthreads quite early, we
|
||||
// have to protect against that in such situations by making a
|
||||
// 'fake' pthread. This is not ideal since it doesn't work well
|
||||
// when linking tcmalloc statically with apps that create threads
|
||||
// before main, so we only do it if we have to.
|
||||
#ifdef PTHREADS_CRASHES_IF_RUN_TOO_EARLY
|
||||
pthread_t me;
|
||||
PerftoolsThreadID me;
|
||||
if (!tsd_inited_) {
|
||||
memset(&me, 0, sizeof(me));
|
||||
} else {
|
||||
me = pthread_self();
|
||||
me = PerftoolsGetThreadID();
|
||||
}
|
||||
#else
|
||||
const pthread_t me = pthread_self();
|
||||
const PerftoolsThreadID me = PerftoolsGetThreadID();
|
||||
#endif
|
||||
|
||||
// This may be a recursive malloc call from pthread_setspecific()
|
||||
// This may be a recursive malloc call from PerftoolsSetTlsValue()
|
||||
// In that case, the heap for this thread has already been created
|
||||
// and added to the linked list. So we search for that first.
|
||||
if (seach_condition) {
|
||||
@ -389,13 +389,13 @@ ThreadCache* ThreadCache::CreateCacheIfNecessary() {
|
||||
if (heap == NULL) heap = NewHeap(me);
|
||||
}
|
||||
|
||||
// We call pthread_setspecific() outside the lock because it may
|
||||
// We call PerftoolsSetTlsValue() outside the lock because it may
|
||||
// call malloc() recursively. We check for the recursive call using
|
||||
// the "in_setspecific_" flag so that we can avoid calling
|
||||
// pthread_setspecific() if we are already inside pthread_setspecific().
|
||||
// PerftoolsSetTlsValue() if we are already inside PerftoolsSetTlsValue().
|
||||
if (!heap->in_setspecific_ && tsd_inited_) {
|
||||
heap->in_setspecific_ = true;
|
||||
perftools_pthread_setspecific(heap_key_, heap);
|
||||
PerftoolsSetTlsValue(heap_key_, heap);
|
||||
#ifdef HAVE_TLS
|
||||
// Also keep a copy in __thread for faster retrieval
|
||||
threadlocal_data_.heap = heap;
|
||||
@ -409,7 +409,7 @@ ThreadCache* ThreadCache::CreateCacheIfNecessary() {
|
||||
return heap;
|
||||
}
|
||||
|
||||
ThreadCache* ThreadCache::NewHeap(pthread_t tid) {
|
||||
ThreadCache* ThreadCache::NewHeap(PerftoolsThreadID tid) {
|
||||
// Create the heap and add it to the linked list
|
||||
ThreadCache *heap = threadcache_allocator.New();
|
||||
heap->Init(tid);
|
||||
@ -434,7 +434,7 @@ void ThreadCache::BecomeIdle() {
|
||||
if (heap->in_setspecific_) return; // Do not disturb the active caller
|
||||
|
||||
heap->in_setspecific_ = true;
|
||||
perftools_pthread_setspecific(heap_key_, NULL);
|
||||
PerftoolsSetTlsValue(heap_key_, NULL);
|
||||
#ifdef HAVE_TLS
|
||||
// Also update the copy in __thread
|
||||
threadlocal_data_.heap = NULL;
|
||||
@ -443,7 +443,7 @@ void ThreadCache::BecomeIdle() {
|
||||
heap->in_setspecific_ = false;
|
||||
if (GetThreadHeap() == heap) {
|
||||
// Somehow heap got reinstated by a recursive call to malloc
|
||||
// from pthread_setspecific. We give up in this case.
|
||||
// from PerftoolsSetTlsValue. We give up in this case.
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -35,13 +35,11 @@
|
||||
#define TCMALLOC_THREAD_CACHE_H_
|
||||
|
||||
#include <config.h>
|
||||
#ifdef HAVE_PTHREAD
|
||||
#include <pthread.h> // for pthread_t, pthread_key_t
|
||||
#endif
|
||||
#include <stddef.h> // for size_t, NULL
|
||||
#include <stdint.h> // for uint32_t, uint64_t
|
||||
#include <sys/types.h> // for ssize_t
|
||||
#include "base/commandlineflags.h"
|
||||
#include "base/threading.h"
|
||||
#include "common.h"
|
||||
#include "linked_list.h"
|
||||
#include "page_heap_allocator.h"
|
||||
@ -57,12 +55,6 @@
|
||||
|
||||
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 {
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
@ -77,7 +69,7 @@ class ThreadCache {
|
||||
enum { have_tls = false };
|
||||
#endif
|
||||
|
||||
void Init(pthread_t tid);
|
||||
void Init(PerftoolsThreadID tid);
|
||||
void Cleanup();
|
||||
|
||||
// Accessors (mostly just for printing stats)
|
||||
@ -268,7 +260,7 @@ class ThreadCache {
|
||||
|
||||
// If TLS is available, we also store a copy of the per-thread object
|
||||
// in a __thread variable since __thread variables are faster to read
|
||||
// than pthread_getspecific(). We still need pthread_setspecific()
|
||||
// than PerftoolsGetTlsValue(). We still need PerftoolsSetTlsValue()
|
||||
// because __thread variables provide no way to run cleanup code when
|
||||
// a thread is destroyed.
|
||||
// We also give a hint to the compiler to use the "initial exec" TLS
|
||||
@ -295,7 +287,7 @@ class ThreadCache {
|
||||
// Therefore, we use TSD keys only after tsd_inited is set to true.
|
||||
// Until then, we use a slow path to get the heap object.
|
||||
static ATTRIBUTE_HIDDEN bool tsd_inited_;
|
||||
static pthread_key_t heap_key_;
|
||||
static PerftoolsTlsKey heap_key_;
|
||||
|
||||
// Linked list of heap objects. Protected by Static::pageheap_lock.
|
||||
static ThreadCache* thread_heaps_;
|
||||
@ -331,11 +323,11 @@ class ThreadCache {
|
||||
// We sample allocations, biased by the size of the allocation
|
||||
Sampler sampler_; // A sampler
|
||||
|
||||
pthread_t tid_; // Which thread owns it
|
||||
bool in_setspecific_; // In call to pthread_setspecific?
|
||||
PerftoolsThreadID tid_; // Which thread owns it
|
||||
bool in_setspecific_; // In call to PerftoolsSetTlsValue?
|
||||
|
||||
// Allocate a new heap. REQUIRES: Static::pageheap_lock is held.
|
||||
static ThreadCache* NewHeap(pthread_t tid);
|
||||
static ThreadCache* NewHeap(PerftoolsThreadID tid);
|
||||
|
||||
// Use only as pthread thread-specific destructor function.
|
||||
static void DestroyThreadCache(void* ptr);
|
||||
@ -411,7 +403,7 @@ inline ThreadCache* ThreadCache::GetThreadHeap() {
|
||||
return threadlocal_data_.heap;
|
||||
#else
|
||||
return reinterpret_cast<ThreadCache *>(
|
||||
perftools_pthread_getspecific(heap_key_));
|
||||
PerftoolsGetTlsValue(heap_key_));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -129,10 +129,6 @@
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
/* #undef HAVE_PTHREAD */
|
||||
|
||||
/* defined to 1 if pthread symbols are exposed even without include pthread.h
|
||||
*/
|
||||
/* #undef HAVE_PTHREAD_DESPITE_ASKING_FOR */
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
/* #undef HAVE_PWD_H */
|
||||
|
||||
|
@ -54,13 +54,6 @@
|
||||
# define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
|
||||
// Some mingw distributions have a pthreads wrapper, but it doesn't
|
||||
// work as well as native windows spinlocks (at least for us). So
|
||||
// pretend the pthreads wrapper doesn't exist, even when it does.
|
||||
#ifndef HAVE_PTHREAD_DESPITE_ASKING_FOR
|
||||
#undef HAVE_PTHREAD
|
||||
#endif
|
||||
|
||||
#undef HAVE_FORK
|
||||
|
||||
#define HAVE_PID_T
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "port.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/spinlock.h"
|
||||
#include "base/threading.h"
|
||||
#include "internal_logging.h"
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
@ -83,7 +84,7 @@ extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) {
|
||||
// -----------------------------------------------------------------------
|
||||
// Threads code
|
||||
|
||||
// Windows doesn't support pthread_key_create's destr_function, and in
|
||||
// Windows doesn't support PerftoolsCreateTlsKey's destr_function, and in
|
||||
// fact it's a bit tricky to get code to run when a thread exits. This
|
||||
// is cargo-cult magic from https://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way
|
||||
// and http://lallouslab.net/2017/05/30/using-cc-tls-callbacks-in-visual-studio-with-your-32-or-64bits-programs/.
|
||||
@ -111,7 +112,7 @@ extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) {
|
||||
#endif
|
||||
|
||||
// When destr_fn eventually runs, it's supposed to take as its
|
||||
// argument the tls-value associated with key that pthread_key_create
|
||||
// argument the tls-value associated with key that PerftoolsCreateTlsKey
|
||||
// creates. (Yeah, it sounds confusing but it's really not.) We
|
||||
// store the destr_fn/key pair in this data structure. Because we
|
||||
// store this in a single var, this implies we can only have one
|
||||
@ -120,7 +121,7 @@ extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) {
|
||||
// into an array.
|
||||
struct DestrFnClosure {
|
||||
void (*destr_fn)(void*);
|
||||
pthread_key_t key_for_destr_fn_arg;
|
||||
PerftoolsTlsKey key_for_destr_fn_arg;
|
||||
};
|
||||
|
||||
static DestrFnClosure destr_fn_info; // initted to all NULL/0.
|
||||
@ -186,11 +187,11 @@ BOOL WINAPI DllMain(HINSTANCE h, DWORD dwReason, PVOID pv) {
|
||||
|
||||
#endif // #ifdef _MSC_VER
|
||||
|
||||
extern "C" pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) {
|
||||
extern "C" PerftoolsTlsKey PthreadKeyCreate(void (*destr_fn)(void*)) {
|
||||
// Semantics are: we create a new key, and then promise to call
|
||||
// destr_fn with TlsGetValue(key) when the thread is destroyed
|
||||
// (as long as TlsGetValue(key) is not NULL).
|
||||
pthread_key_t key = TlsAlloc();
|
||||
PerftoolsTlsKey key = TlsAlloc();
|
||||
if (destr_fn) { // register it
|
||||
// If this assert fails, we'll need to support an array of destr_fn_infos
|
||||
assert(destr_fn_info.destr_fn == NULL);
|
||||
|
@ -108,61 +108,6 @@ typedef intptr_t ssize_t;
|
||||
|
||||
/* ----------------------------------- THREADS */
|
||||
|
||||
#ifndef HAVE_PTHREAD /* not true for MSVC, but may be true for MSYS */
|
||||
typedef DWORD pthread_t;
|
||||
typedef DWORD pthread_key_t;
|
||||
|
||||
inline pthread_t pthread_self(void) {
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
inline bool pthread_equal(pthread_t left, pthread_t right) {
|
||||
return left == right;
|
||||
}
|
||||
|
||||
/*
|
||||
* windows/port.h defines compatibility APIs for several .h files, which
|
||||
* we therefore shouldn't be #including directly. This hack keeps us from
|
||||
* doing so. TODO(csilvers): do something more principled.
|
||||
*/
|
||||
#define HAVE_PERFTOOLS_PTHREAD_KEYS
|
||||
|
||||
EXTERN_C pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)); /* port.cc */
|
||||
|
||||
inline int perftools_pthread_key_create(pthread_key_t *pkey,
|
||||
void (*destructor)(void*)) {
|
||||
pthread_key_t key = PthreadKeyCreate(destructor);
|
||||
if (key != TLS_OUT_OF_INDEXES) {
|
||||
*(pkey) = key;
|
||||
return 0;
|
||||
} else {
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
inline void* perftools_pthread_getspecific(DWORD key) {
|
||||
DWORD err = GetLastError();
|
||||
void* rv = TlsGetValue(key);
|
||||
if (err) SetLastError(err);
|
||||
return rv;
|
||||
}
|
||||
|
||||
inline int perftools_pthread_setspecific(pthread_key_t key, const void *value) {
|
||||
if (TlsSetValue(key, (LPVOID)value))
|
||||
return 0;
|
||||
else
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
inline void sched_yield(void) {
|
||||
Sleep(0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_PTHREAD */
|
||||
|
||||
/*
|
||||
* __declspec(thread) isn't usable in a dll opened via LoadLibrary().
|
||||
* But it doesn't work to LoadLibrary() us anyway, because of all the
|
||||
|
Loading…
Reference in New Issue
Block a user