Chromium Code Reviews| Index: tools/cygprofile/cygprofile.cc |
| diff --git a/tools/cygprofile/cygprofile.cc b/tools/cygprofile/cygprofile.cc |
| index d699c3e355bd255250df242b449a4a9424bc8b67..368a633c95d4ef6f9ac6b7c3503f837579c8c715 100644 |
| --- a/tools/cygprofile/cygprofile.cc |
| +++ b/tools/cygprofile/cygprofile.cc |
| @@ -51,7 +51,25 @@ 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 otpimizations, as this need to be read in re-entrant code. |
| +// This variable is NOT accessed from multiple threads (pthread_once guarantees |
|
pasko
2016/04/15 11:42:14
as per offline discussion, this comment needs to b
Primiano Tucci (use gerrit)
2016/04/15 12:51:07
Done.
|
| +// that). |
| +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; |
| + (void) pthread_key_create(&g_tls_slot, NULL); |
|
pasko
2016/04/15 11:42:14
Everywhere in this file please check return value
Primiano Tucci (use gerrit)
2016/04/15 12:51:07
Went for CHECK. perror doesn't really help on andr
|
| + g_tls_slot_being_initialized = false; |
| +} |
| // Returns light-weight process ID. On Linux, this is a system-wide unique |
| // thread id. |
| @@ -163,8 +181,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. |
| + pthread_setspecific(g_tls_slot, kMagicBeingConstructed); |
| Thread* const instance = reinterpret_cast<Thread*>(data); |
| instance->thread_callback_.Run(); |
| @@ -199,7 +220,7 @@ ThreadLog::ThreadLog(const FlushCallback& flush_callback) |
| } |
| ThreadLog::~ThreadLog() { |
| - g_tls_log = NULL; |
| + pthread_setspecific(g_tls_slot, NULL); |
| } |
| void ThreadLog::AddEntry(void* address) { |
| @@ -358,16 +379,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) { |
| + pthread_setspecific(g_tls_slot, kMagicBeingConstructed); |
| + thread_log = new ThreadLog(); |
| + CHECK(thread_log); |
| + g_logs_manager.Pointer()->AddLog(base::WrapUnique(thread_log)); |
| + 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) {} |