Commit f581614a authored by Mike Percy's avatar Mike Percy

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.
parent b6a5e052
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment