5de29b
diff -pruN a/nptl/sysdeps/pthread/unwind-forcedunwind.c b/nptl/sysdeps/pthread/unwind-forcedunwind.c
5de29b
--- a/nptl/sysdeps/pthread/unwind-forcedunwind.c	2010-05-04 16:57:23.000000000 +0530
5de29b
+++ b/nptl/sysdeps/pthread/unwind-forcedunwind.c	2014-06-02 23:00:02.901013275 +0530
5de29b
@@ -45,8 +45,10 @@ pthread_cancel_init (void)
5de29b
 
5de29b
   if (__builtin_expect (libgcc_s_handle != NULL, 1))
5de29b
     {
5de29b
-      /* Force gcc to reload all values.  */
5de29b
-      asm volatile ("" ::: "memory");
5de29b
+      /* Order reads so as to prevent speculation of loads
5de29b
+	 of libgcc_s_{resume,personality,forcedunwind,getcfa}
5de29b
+	 to points prior to the write barrier.  */
5de29b
+      atomic_read_barrier ();
5de29b
       return;
5de29b
     }
5de29b
 
5de29b
@@ -72,9 +74,14 @@ pthread_cancel_init (void)
5de29b
   libgcc_s_forcedunwind = forcedunwind;
5de29b
   PTR_MANGLE (getcfa);
5de29b
   libgcc_s_getcfa = getcfa;
5de29b
-  /* Make sure libgcc_s_handle is written last.  Otherwise,
5de29b
-     pthread_cancel_init might return early even when the pointer the
5de29b
-     caller is interested in is not initialized yet.  */
5de29b
+  /* At the point at which any thread writes the handle
5de29b
+     to libgcc_s_handle, the initialization is complete.
5de29b
+     The writing of libgcc_s_handle is atomic. All other
5de29b
+     threads reading libgcc_s_handle do so atomically. Any
5de29b
+     thread that does not execute this function must issue
5de29b
+     a read barrier to ensure that all of the above has
5de29b
+     actually completed and that the values of the
5de29b
+     function pointers are correct.   */
5de29b
   atomic_write_barrier ();
5de29b
   libgcc_s_handle = handle;
5de29b
 }
5de29b
@@ -91,13 +98,19 @@ __unwind_freeres (void)
5de29b
     }
5de29b
 }
5de29b
 
5de29b
-void
5de29b
-_Unwind_Resume (struct _Unwind_Exception *exc)
5de29b
+static __always_inline void
5de29b
+_maybe_pthread_cancel_init (void)
5de29b
 {
5de29b
   if (__builtin_expect (libgcc_s_handle == NULL, 0))
5de29b
     pthread_cancel_init ();
5de29b
   else
5de29b
     atomic_read_barrier ();
5de29b
+}
5de29b
+
5de29b
+void
5de29b
+_Unwind_Resume (struct _Unwind_Exception *exc)
5de29b
+{
5de29b
+  _maybe_pthread_cancel_init ();
5de29b
 
5de29b
   void (*resume) (struct _Unwind_Exception *exc) = libgcc_s_resume;
5de29b
   PTR_DEMANGLE (resume);
5de29b
@@ -108,10 +123,7 @@ __gcc_personality_v0 (int version, _Unwi
5de29b
 		      struct _Unwind_Exception *ue_header,
5de29b
 		      struct _Unwind_Context *context)
5de29b
 {
5de29b
-  if (__builtin_expect (libgcc_s_handle == NULL, 0))
5de29b
-    pthread_cancel_init ();
5de29b
-  else
5de29b
-    atomic_read_barrier ();
5de29b
+  _maybe_pthread_cancel_init ();
5de29b
 
5de29b
   _Unwind_Reason_Code (*personality)
5de29b
     (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
5de29b
@@ -122,10 +136,7 @@ _Unwind_Reason_Code
5de29b
 _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
5de29b
 		      void *stop_argument)
5de29b
 {
5de29b
-  if (__builtin_expect (libgcc_s_handle == NULL, 0))
5de29b
-    pthread_cancel_init ();
5de29b
-  else
5de29b
-    atomic_read_barrier ();
5de29b
+  _maybe_pthread_cancel_init ();
5de29b
 
5de29b
   _Unwind_Reason_Code (*forcedunwind)
5de29b
     (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *)
5de29b
@@ -135,10 +148,7 @@ _Unwind_ForcedUnwind (struct _Unwind_Exc
5de29b
 _Unwind_Word
5de29b
 _Unwind_GetCFA (struct _Unwind_Context *context)
5de29b
 {
5de29b
-  if (__builtin_expect (libgcc_s_handle == NULL, 0))
5de29b
-    pthread_cancel_init ();
5de29b
-  else
5de29b
-    atomic_read_barrier ();
5de29b
+  _maybe_pthread_cancel_init ();
5de29b
 
5de29b
   _Unwind_Word (*getcfa) (struct _Unwind_Context *) = libgcc_s_getcfa;
5de29b
   PTR_DEMANGLE (getcfa);
5de29b
diff -pruN a/sysdeps/gnu/unwind-resume.c b/sysdeps/gnu/unwind-resume.c
5de29b
--- a/sysdeps/gnu/unwind-resume.c	2010-05-04 16:57:23.000000000 +0530
5de29b
+++ b/sysdeps/gnu/unwind-resume.c	2014-06-02 23:02:26.812007078 +0530
5de29b
@@ -20,8 +20,11 @@
5de29b
 #include <dlfcn.h>
5de29b
 #include <stdio.h>
5de29b
 #include <unwind.h>
5de29b
+#include <pthreadP.h>
5de29b
+#include <sysdep.h>
5de29b
 #include <gnu/lib-names.h>
5de29b
 
5de29b
+static void *libgcc_s_handle;
5de29b
 static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
5de29b
 static _Unwind_Reason_Code (*libgcc_s_personality)
5de29b
   (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
5de29b
@@ -42,13 +45,32 @@ init (void)
5de29b
 
5de29b
   libgcc_s_resume = resume;
5de29b
   libgcc_s_personality = personality;
5de29b
+  atomic_write_barrier ();
5de29b
+  /* At the point at which any thread writes the handle
5de29b
+     to libgcc_s_handle, the initialization is complete.
5de29b
+     The writing of libgcc_s_handle is atomic. All other
5de29b
+     threads reading libgcc_s_handle do so atomically. Any
5de29b
+     thread that does not execute this function must issue
5de29b
+     a read barrier to ensure that all of the above has
5de29b
+     actually completed and that the values of the
5de29b
+     function pointers are correct.   */
5de29b
+  libgcc_s_handle = handle;
5de29b
 }
5de29b
 
5de29b
+static __always_inline void
5de29b
+_maybe_init (void)
5de29b
+{
5de29b
+  if (__builtin_expect (libgcc_s_handle == NULL, 0))
5de29b
+    init ();
5de29b
+  else
5de29b
+    atomic_read_barrier ();
5de29b
+}
5de29b
+
5de29b
+
5de29b
 void
5de29b
 _Unwind_Resume (struct _Unwind_Exception *exc)
5de29b
 {
5de29b
-  if (__builtin_expect (libgcc_s_resume == NULL, 0))
5de29b
-    init ();
5de29b
+  _maybe_init ();
5de29b
   libgcc_s_resume (exc);
5de29b
 }
5de29b
 
5de29b
@@ -58,8 +80,7 @@ __gcc_personality_v0 (int version, _Unwi
5de29b
                       struct _Unwind_Exception *ue_header,
5de29b
                       struct _Unwind_Context *context)
5de29b
 {
5de29b
-  if (__builtin_expect (libgcc_s_personality == NULL, 0))
5de29b
-    init ();
5de29b
+  _maybe_init ();
5de29b
   return libgcc_s_personality (version, actions, exception_class,
5de29b
 			       ue_header, context);
5de29b
 }