@@ -60,30 +60,54 @@ inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int
6060 // Do nothing, just return.
6161}
6262
63+ // Not async-signal-safe, so this method is not called from async-safe functions.
64+ //
65+ // This function is not async signal safe because:
66+ // * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
67+ // * No guarantees on `backtrace_create_state` function.
68+ //
69+ // Currently `backtrace_create_state` can not detect file name on Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82543
70+ // That's why we provide a `prog_location` here.
71+ BOOST_SYMBOL_VISIBLE inline ::backtrace_state* construct_state (const program_location& prog_location) BOOST_NOEXCEPT {
72+ // [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
6373
64- inline ::backtrace_state* construct_state ( const program_location& prog_location) BOOST_NOEXCEPT {
65- // Currently `backtrace_create_state` can not detect file name on Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82543
66- // That's why we provide a `prog_location` here.
67- return :: backtrace_create_state (
68- prog_location. name (), 0 /* thread-safe */ , boost::stacktrace::detail::libbacktrace_error_callback, 0
69- );
70-
71- // TODO: this does not seem to work well when this function is in .so:
72- // Not async-signal-safe, so this method is not called from async-safe functions.
74+ // TODO: The most obvious solution:
75+ //
76+ // static ::backtrace_state* state = ::backtrace_create_state(
77+ // prog_location.name(),
78+ // 1, // allow safe concurrent usage of the same state
79+ // boost::stacktrace::detail::libbacktrace_error_callback,
80+ // 0 // pointer to data that will be passed to callback
81+ // );
82+ //
7383 //
74- // This function is not async signal safe because:
75- // * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
76- // * No guarantees on `backtrace_create_state` function.
84+ // Unfortunately, that solution segfaults when `construct_state()` function is in .so file
85+ // and multiple threads concurrently work with state.
7786
78- // [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
7987
80- /*
81- static ::backtrace_state* state = ::backtrace_create_state(
82- 0, 1 , boost::stacktrace::detail::libbacktrace_error_callback, 0
83- );
88+ #ifndef BOOST_HAS_THREADS
89+ static
90+ #else
91+
92+ // Result of `construct_state()` invocation is not stored by the callers, so `thread_local`
93+ // gives a single `state` per thread and that state is not shared between threads in any way.
8494
95+ # ifndef BOOST_NO_CXX11_THREAD_LOCAL
96+ thread_local
97+ # elif defined(__GNUC__)
98+ static __thread
99+ # else
100+ /* just a local variable */
101+ # endif
102+
103+ #endif
104+ ::backtrace_state* state = ::backtrace_create_state (
105+ prog_location.name (),
106+ 0 ,
107+ boost::stacktrace::detail::libbacktrace_error_callback,
108+ 0
109+ );
85110 return state;
86- */
87111}
88112
89113struct to_string_using_backtrace {
0 commit comments