Index: tools/cygprofile/cygprofile.cc |
diff --git a/tools/cygprofile/cygprofile.cc b/tools/cygprofile/cygprofile.cc |
index d699c3e355bd255250df242b449a4a9424bc8b67..af0a2a73a2ab494cc4df1dd3b52f585139d8c984 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 otpimizations, as this need to be read re-entratively. |
pasko
2016/04/15 13:00:47
nit: s/read re-entratively/read in a re-entrant wa
Primiano Tucci (use gerrit)
2016/04/15 13:06:08
Done.
|
+// 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; |
+ CHECK_EQ(0, pthread_key_create(&g_tls_slot, NULL)); |
pasko
2016/04/15 13:00:47
let's do a PCHECK(pthread_key_create(&g_tls_slot,
pasko
2016/04/15 13:03:59
plz disregard this (it returns zero on success, an
Primiano Tucci (use gerrit)
2016/04/15 13:06:08
Done.
Primiano Tucci (use gerrit)
2016/04/15 13:06:08
Done.
|
+ g_tls_slot_being_initialized = false; |
+} |
// Returns light-weight process ID. On Linux, this is a system-wide unique |
// thread id. |
@@ -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. |
+ CHECK_EQ(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; |
+ CHECK_EQ(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) { |
+ CHECK_EQ(0, pthread_setspecific(g_tls_slot, kMagicBeingConstructed)); |
+ thread_log = new ThreadLog(); |
+ CHECK(thread_log); |
+ g_logs_manager.Pointer()->AddLog(base::WrapUnique(thread_log)); |
+ CHECK_EQ(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) {} |