diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 73e3a4f6d6f..b5c7ea4a9af 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,14 @@ +2016-09-16 Jakub Jelinek + + PR libgcc/71744 + * unwind-dw2-fde.c (ATOMIC_FDE_FAST_PATH): Define if __register_frame* + is not the primary registry and atomics are available. + (any_objects_registered): New variable. + (__register_frame_info_bases, __register_frame_info_table_bases): + Atomically store 1 to any_objects_registered after registering first + unwind info. + (_Unwind_Find_FDE): Return early if any_objects_registered is 0. + 2016-09-09 James Greenhalgh PR target/63250 diff --git a/libgcc/unwind-dw2-fde.c b/libgcc/unwind-dw2-fde.c index 5b16a1f87e2..be82f65b916 100644 --- a/libgcc/unwind-dw2-fde.c +++ b/libgcc/unwind-dw2-fde.c @@ -35,6 +35,11 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include "unwind-pe.h" #include "unwind-dw2-fde.h" #include "gthr.h" +#else +#if (defined(__GTHREAD_MUTEX_INIT) || defined(__GTHREAD_MUTEX_INIT_FUNCTION)) \ + && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) +#define ATOMIC_FDE_FAST_PATH 1 +#endif #endif /* The unseen_objects list contains objects that have been registered @@ -43,6 +48,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see by decreasing value of pc_begin. */ static struct object *unseen_objects; static struct object *seen_objects; +#ifdef ATOMIC_FDE_FAST_PATH +static int any_objects_registered; +#endif #ifdef __GTHREAD_MUTEX_INIT static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT; @@ -96,6 +104,16 @@ __register_frame_info_bases (const void *begin, struct object *ob, ob->next = unseen_objects; unseen_objects = ob; +#ifdef ATOMIC_FDE_FAST_PATH + /* Set flag that at least one library has registered FDEs. + Use relaxed MO here, it is up to the app to ensure that the library + loading/initialization happens-before using that library in other + threads (in particular unwinding with that library's functions + appearing in the backtraces). Calling that library's functions + without waiting for the library to initialize would be racy. */ + if (!any_objects_registered) + __atomic_store_n (&any_objects_registered, 1, __ATOMIC_RELAXED); +#endif __gthread_mutex_unlock (&object_mutex); } @@ -140,6 +158,16 @@ __register_frame_info_table_bases (void *begin, struct object *ob, ob->next = unseen_objects; unseen_objects = ob; +#ifdef ATOMIC_FDE_FAST_PATH + /* Set flag that at least one library has registered FDEs. + Use relaxed MO here, it is up to the app to ensure that the library + loading/initialization happens-before using that library in other + threads (in particular unwinding with that library's functions + appearing in the backtraces). Calling that library's functions + without waiting for the library to initialize would be racy. */ + if (!any_objects_registered) + __atomic_store_n (&any_objects_registered, 1, __ATOMIC_RELAXED); +#endif __gthread_mutex_unlock (&object_mutex); } @@ -1001,6 +1029,19 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases) struct object *ob; const fde *f = NULL; +#ifdef ATOMIC_FDE_FAST_PATH + /* For targets where unwind info is usually not registered through these + APIs anymore, avoid taking a global lock. + Use relaxed MO here, it is up to the app to ensure that the library + loading/initialization happens-before using that library in other + threads (in particular unwinding with that library's functions + appearing in the backtraces). Calling that library's functions + without waiting for the library to initialize would be racy. */ + if (__builtin_expect (!__atomic_load_n (&any_objects_registered, + __ATOMIC_RELAXED), 1)) + return NULL; +#endif + init_object_mutex_once (); __gthread_mutex_lock (&object_mutex);