From f581614a78c68da17700b039ea69c774c1c6b892 Mon Sep 17 00:00:00 2001 From: Mike Percy Date: Fri, 27 Jan 2017 20:45:26 -0800 Subject: [PATCH] Use thread local for libunwind GetStackTrace() Previously, the implementation of google::GetStackTrace() that uses libunwind uses a global variable that enforces that only one thread may invoke libunwind at a time. However, libunwind is thread-safe. The comment above the variable indicates that it is to protect against reentrancy issues. Instead of using a global variable, it would be much better to use a thread-local variable to protect against these reentrancy issues. That should provide the needed reentrancy protection while allowing multiple threads to get stack traces at the same time. It also allows for the removal of the atomic CAS operations on the variable. Resolves #160. --- src/stacktrace_libunwind-inl.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/stacktrace_libunwind-inl.h b/src/stacktrace_libunwind-inl.h index 0dc14c650..e29a50c00 100644 --- a/src/stacktrace_libunwind-inl.h +++ b/src/stacktrace_libunwind-inl.h @@ -49,7 +49,9 @@ _START_GOOGLE_NAMESPACE_ // recursive request, we'd end up with infinite recursion or deadlock. // Luckily, it's safe to ignore those subsequent traces. In such // cases, we return 0 to indicate the situation. -static bool g_now_entering = false; +// We can use the GCC __thread syntax here since libunwind is not supported on +// Windows. +static __thread bool g_tl_entered; // Initialized to false. // If you change this function, also change GetStackFrames below. int GetStackTrace(void** result, int max_depth, int skip_count) { @@ -58,9 +60,10 @@ int GetStackTrace(void** result, int max_depth, int skip_count) { unw_cursor_t cursor; unw_context_t uc; - if (sync_val_compare_and_swap(&g_now_entering, false, true)) { + if (g_tl_entered) { return 0; } + g_tl_entered = true; unw_getcontext(&uc); RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed"); @@ -80,7 +83,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) { break; } - g_now_entering = false; + g_tl_entered = false; return n; }