| Index: tools/cygprofile/cygprofile.cc
|
| diff --git a/tools/cygprofile/cygprofile.cc b/tools/cygprofile/cygprofile.cc
|
| index d699c3e355bd255250df242b449a4a9424bc8b67..c7f12e8b49f62a76ada01584c596cdc22ab1a447 100644
|
| --- a/tools/cygprofile/cygprofile.cc
|
| +++ b/tools/cygprofile/cygprofile.cc
|
| @@ -51,7 +51,27 @@ const char kLogFilenameFormat[] = "%scyglog.%d.%d-%d";
|
| ThreadLog* const kMagicBeingConstructed = reinterpret_cast<ThreadLog*>(1);
|
|
|
| // Per-thread pointer to the current log object.
|
| -static __thread ThreadLog* g_tls_log = NULL;
|
| +pthread_key_t g_tls_slot;
|
| +
|
| +// Used to initialize the tls slot, once per the entire process.
|
| +pthread_once_t g_tls_slot_initializer_once = PTHREAD_ONCE_INIT;
|
| +
|
| +// This variable is to prevent re-entrancy in the __cyg_profile_func_enter()
|
| +// while the TLS slot itself is being initialized. Volatile here is required
|
| +// to avoid compiler optimizations as this need to be read in a re-entrant way.
|
| +// This variable is written by one thread only, which is the first thread that
|
| +// happens to run the TLSSlotInitializer(). In practice this will happen very
|
| +// early in the startup process, as soon as the first instrumented function is
|
| +// called.
|
| +volatile bool g_tls_slot_being_initialized = false;
|
| +
|
| +// Initializes the global TLS slot. This is invoked only once per process.
|
| +static void TLSSlotInitializer()
|
| +{
|
| + g_tls_slot_being_initialized = true;
|
| + PCHECK(0 == pthread_key_create(&g_tls_slot, NULL));
|
| + g_tls_slot_being_initialized = false;
|
| +}
|
|
|
| // Returns light-weight process ID. On Linux, this is a system-wide unique
|
| // thread id.
|
| @@ -151,11 +171,11 @@ class Thread {
|
| public:
|
| Thread(const base::Closure& thread_callback)
|
| : thread_callback_(thread_callback) {
|
| - CHECK_EQ(0, pthread_create(&handle_, NULL, &Thread::EntryPoint, this));
|
| + PCHECK(0 == pthread_create(&handle_, NULL, &Thread::EntryPoint, this));
|
| }
|
|
|
| ~Thread() {
|
| - CHECK_EQ(0, pthread_join(handle_, NULL));
|
| + PCHECK(0 == pthread_join(handle_, NULL));
|
| }
|
|
|
| private:
|
| @@ -163,8 +183,11 @@ class Thread {
|
| // Disable logging on this thread. Although this routine is not instrumented
|
| // (cygprofile.gyp provides that), the called routines are and thus will
|
| // call instrumentation.
|
| - CHECK(g_tls_log == NULL); // Must be 0 as this is a new thread.
|
| - g_tls_log = kMagicBeingConstructed;
|
| + pthread_once(&g_tls_slot_initializer_once, TLSSlotInitializer);
|
| + ThreadLog* thread_log = reinterpret_cast<ThreadLog*>(
|
| + pthread_getspecific(g_tls_slot));
|
| + CHECK(thread_log == NULL); // Must be 0 as this is a new thread.
|
| + PCHECK(0 == pthread_setspecific(g_tls_slot, kMagicBeingConstructed));
|
|
|
| Thread* const instance = reinterpret_cast<Thread*>(data);
|
| instance->thread_callback_.Run();
|
| @@ -199,7 +222,7 @@ ThreadLog::ThreadLog(const FlushCallback& flush_callback)
|
| }
|
|
|
| ThreadLog::~ThreadLog() {
|
| - g_tls_log = NULL;
|
| + PCHECK(0 == pthread_setspecific(g_tls_slot, NULL));
|
| }
|
|
|
| void ThreadLog::AddEntry(void* address) {
|
| @@ -358,16 +381,24 @@ void __cyg_profile_func_exit(void* this_fn, void* call_site)
|
| __attribute__((no_instrument_function));
|
|
|
| void __cyg_profile_func_enter(void* this_fn, void* callee_unused) {
|
| - if (g_tls_log == NULL) {
|
| - g_tls_log = kMagicBeingConstructed;
|
| - ThreadLog* new_log = new ThreadLog();
|
| - CHECK(new_log);
|
| - g_logs_manager.Pointer()->AddLog(base::WrapUnique(new_log));
|
| - g_tls_log = new_log;
|
| + // Avoid re-entrancy while initializing the TLS slot (once per process).
|
| + if (g_tls_slot_being_initialized)
|
| + return;
|
| +
|
| + pthread_once(&g_tls_slot_initializer_once, TLSSlotInitializer);
|
| + ThreadLog* thread_log = reinterpret_cast<ThreadLog*>(
|
| + pthread_getspecific(g_tls_slot));
|
| +
|
| + if (thread_log == NULL) {
|
| + PCHECK(0 == pthread_setspecific(g_tls_slot, kMagicBeingConstructed));
|
| + thread_log = new ThreadLog();
|
| + CHECK(thread_log);
|
| + g_logs_manager.Pointer()->AddLog(base::WrapUnique(thread_log));
|
| + PCHECK(0 == pthread_setspecific(g_tls_slot, thread_log));
|
| }
|
|
|
| - if (g_tls_log != kMagicBeingConstructed)
|
| - g_tls_log->AddEntry(this_fn);
|
| + if (thread_log != kMagicBeingConstructed)
|
| + thread_log->AddEntry(this_fn);
|
| }
|
|
|
| void __cyg_profile_func_exit(void* this_fn, void* call_site) {}
|
|
|