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