mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2025-02-02 20:52:55 +01:00
pthread_once() workaround for FreeBSD and Solaris
On FreeBSD, as well as on the Solaris < 10, weak pthread_once stub is always exported from libc. But it does nothing, which means that if threaded library is not loaded, then pthread_once() call do not actually call the initializer finction. The construct if (likely (pthread_once != 0)) { pthread_once(&trace_cache_once, &trace_cache_init_once); then fails to initialize the trace cache on x86_64. Work around by checking that the initializer was indeed called. Note that this can break if libthr is loaded dynamically, but my belief is that there is no platforms which allow dynamic loading of the threading library.
This commit is contained in:
parent
9a311bf48b
commit
08077a4962
1 changed files with 25 additions and 12 deletions
|
@ -50,6 +50,7 @@ typedef struct
|
|||
static const unw_tdep_frame_t empty_frame = { 0, UNW_X86_64_FRAME_OTHER, -1, -1, 0, -1, -1 };
|
||||
static pthread_mutex_t trace_init_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_once_t trace_cache_once = PTHREAD_ONCE_INIT;
|
||||
static sig_atomic_t trace_cache_once_happen;
|
||||
static pthread_key_t trace_cache_key;
|
||||
static struct mempool trace_cache_pool;
|
||||
|
||||
|
@ -69,6 +70,7 @@ trace_cache_init_once (void)
|
|||
{
|
||||
pthread_key_create (&trace_cache_key, &trace_cache_free);
|
||||
mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0);
|
||||
trace_cache_once_happen = 1;
|
||||
}
|
||||
|
||||
static unw_tdep_frame_t *
|
||||
|
@ -137,6 +139,24 @@ trace_cache_expand (unw_trace_cache_t *cache)
|
|||
|
||||
static __thread unw_trace_cache_t *tls_cache;
|
||||
|
||||
static unw_trace_cache_t *
|
||||
trace_cache_get_unthreaded (void)
|
||||
{
|
||||
unw_trace_cache_t *cache;
|
||||
intrmask_t saved_mask;
|
||||
static unw_trace_cache_t *global_cache = 0;
|
||||
lock_acquire (&trace_init_lock, saved_mask);
|
||||
if (! global_cache)
|
||||
{
|
||||
mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0);
|
||||
global_cache = trace_cache_create ();
|
||||
}
|
||||
cache = global_cache;
|
||||
lock_release (&trace_init_lock, saved_mask);
|
||||
Debug(5, "using cache %p\n", cache);
|
||||
return cache;
|
||||
}
|
||||
|
||||
/* Get the frame cache for the current thread. Create it if there is none. */
|
||||
static unw_trace_cache_t *
|
||||
trace_cache_get (void)
|
||||
|
@ -145,6 +165,10 @@ trace_cache_get (void)
|
|||
if (likely (pthread_once != 0))
|
||||
{
|
||||
pthread_once(&trace_cache_once, &trace_cache_init_once);
|
||||
if (!trace_cache_once_happen)
|
||||
{
|
||||
return trace_cache_get_unthreaded();
|
||||
}
|
||||
if (! (cache = tls_cache))
|
||||
{
|
||||
cache = trace_cache_create();
|
||||
|
@ -156,18 +180,7 @@ trace_cache_get (void)
|
|||
}
|
||||
else
|
||||
{
|
||||
intrmask_t saved_mask;
|
||||
static unw_trace_cache_t *global_cache = 0;
|
||||
lock_acquire (&trace_init_lock, saved_mask);
|
||||
if (! global_cache)
|
||||
{
|
||||
mempool_init (&trace_cache_pool, sizeof (unw_trace_cache_t), 0);
|
||||
global_cache = trace_cache_create ();
|
||||
}
|
||||
cache = global_cache;
|
||||
lock_release (&trace_init_lock, saved_mask);
|
||||
Debug(5, "using cache %p\n", cache);
|
||||
return cache;
|
||||
return trace_cache_get_unthreaded();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue