coarray_43.f90: Add "-latomic" option if libatomic_available.
[gcc.git] / libgcc / unwind-dw2-fde.c
index 7a783329f7cad4988e2e7bf3740d1067065a1159..02b588de89212cc9b85cbc32e121b224fa2089f5 100644 (file)
@@ -1,6 +1,5 @@
 /* Subroutines needed for unwinding stack frames for exception handling.  */
-/* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
-   2009, 2010, 2011  Free Software Foundation, Inc.
+/* Copyright (C) 1997-2017 Free Software Foundation, Inc.
    Contributed by Jason Merrill <jason@cygnus.com>.
 
 This file is part of GCC.
@@ -36,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
@@ -44,14 +48,17 @@ 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;
+#define init_object_mutex_once()
 #else
+#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
 static __gthread_mutex_t object_mutex;
-#endif
 
-#ifdef __GTHREAD_MUTEX_INIT_FUNCTION
 static void
 init_object_mutex (void)
 {
@@ -65,7 +72,11 @@ init_object_mutex_once (void)
   __gthread_once (&once, init_object_mutex);
 }
 #else
+/* ???  Several targets include this file with stubbing parts of gthr.h
+   and expect no locking to be done.  */
 #define init_object_mutex_once()
+static __gthread_mutex_t object_mutex;
+#endif
 #endif
 
 /* Called from crtbegin.o to register the unwind info for an object.  */
@@ -93,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);
 }
@@ -137,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);
 }
@@ -998,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);