]>
Commit | Line | Data |
---|---|---|
bb330e25 AF |
1 | diff -pruN a/nptl/sysdeps/pthread/unwind-forcedunwind.c b/nptl/sysdeps/pthread/unwind-forcedunwind.c |
2 | --- a/nptl/sysdeps/pthread/unwind-forcedunwind.c 2010-05-04 16:57:23.000000000 +0530 | |
3 | +++ b/nptl/sysdeps/pthread/unwind-forcedunwind.c 2014-06-02 23:00:02.901013275 +0530 | |
4 | @@ -45,8 +45,10 @@ pthread_cancel_init (void) | |
5 | ||
6 | if (__builtin_expect (libgcc_s_handle != NULL, 1)) | |
7 | { | |
8 | - /* Force gcc to reload all values. */ | |
9 | - asm volatile ("" ::: "memory"); | |
10 | + /* Order reads so as to prevent speculation of loads | |
11 | + of libgcc_s_{resume,personality,forcedunwind,getcfa} | |
12 | + to points prior to the write barrier. */ | |
13 | + atomic_read_barrier (); | |
14 | return; | |
15 | } | |
16 | ||
17 | @@ -72,9 +74,14 @@ pthread_cancel_init (void) | |
18 | libgcc_s_forcedunwind = forcedunwind; | |
19 | PTR_MANGLE (getcfa); | |
20 | libgcc_s_getcfa = getcfa; | |
21 | - /* Make sure libgcc_s_handle is written last. Otherwise, | |
22 | - pthread_cancel_init might return early even when the pointer the | |
23 | - caller is interested in is not initialized yet. */ | |
24 | + /* At the point at which any thread writes the handle | |
25 | + to libgcc_s_handle, the initialization is complete. | |
26 | + The writing of libgcc_s_handle is atomic. All other | |
27 | + threads reading libgcc_s_handle do so atomically. Any | |
28 | + thread that does not execute this function must issue | |
29 | + a read barrier to ensure that all of the above has | |
30 | + actually completed and that the values of the | |
31 | + function pointers are correct. */ | |
32 | atomic_write_barrier (); | |
33 | libgcc_s_handle = handle; | |
34 | } | |
35 | @@ -91,11 +98,19 @@ __unwind_freeres (void) | |
36 | } | |
37 | } | |
38 | ||
39 | -void | |
40 | -_Unwind_Resume (struct _Unwind_Exception *exc) | |
41 | +static __always_inline void | |
42 | +_maybe_pthread_cancel_init (void) | |
43 | { | |
44 | if (__builtin_expect (libgcc_s_handle == NULL, 0)) | |
45 | pthread_cancel_init (); | |
46 | + else | |
47 | + atomic_read_barrier (); | |
48 | +} | |
49 | + | |
50 | +void | |
51 | +_Unwind_Resume (struct _Unwind_Exception *exc) | |
52 | +{ | |
53 | + _maybe_pthread_cancel_init (); | |
54 | ||
55 | void (*resume) (struct _Unwind_Exception *exc) = libgcc_s_resume; | |
56 | PTR_DEMANGLE (resume); | |
57 | @@ -108,8 +123,7 @@ __gcc_personality_v0 (int version, _Unwi | |
58 | struct _Unwind_Exception *ue_header, | |
59 | struct _Unwind_Context *context) | |
60 | { | |
61 | - if (__builtin_expect (libgcc_s_handle == NULL, 0)) | |
62 | - pthread_cancel_init (); | |
63 | + _maybe_pthread_cancel_init (); | |
64 | ||
65 | _Unwind_Reason_Code (*personality) | |
66 | (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, | |
67 | @@ -122,8 +136,7 @@ _Unwind_Reason_Code | |
68 | _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop, | |
69 | void *stop_argument) | |
70 | { | |
71 | - if (__builtin_expect (libgcc_s_handle == NULL, 0)) | |
72 | - pthread_cancel_init (); | |
73 | + _maybe_pthread_cancel_init (); | |
74 | ||
75 | _Unwind_Reason_Code (*forcedunwind) | |
76 | (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *) | |
77 | @@ -135,8 +148,7 @@ _Unwind_ForcedUnwind (struct _Unwind_Exc | |
78 | _Unwind_Word | |
79 | _Unwind_GetCFA (struct _Unwind_Context *context) | |
80 | { | |
81 | - if (__builtin_expect (libgcc_s_handle == NULL, 0)) | |
82 | - pthread_cancel_init (); | |
83 | + _maybe_pthread_cancel_init (); | |
84 | ||
85 | _Unwind_Word (*getcfa) (struct _Unwind_Context *) = libgcc_s_getcfa; | |
86 | PTR_DEMANGLE (getcfa); | |
87 | diff -pruN a/sysdeps/gnu/unwind-resume.c b/sysdeps/gnu/unwind-resume.c | |
88 | --- a/sysdeps/gnu/unwind-resume.c 2010-05-04 16:57:23.000000000 +0530 | |
89 | +++ b/sysdeps/gnu/unwind-resume.c 2014-06-02 23:02:26.812007078 +0530 | |
90 | @@ -20,8 +20,11 @@ | |
91 | #include <dlfcn.h> | |
92 | #include <stdio.h> | |
93 | #include <unwind.h> | |
94 | +#include <pthreadP.h> | |
95 | +#include <sysdep.h> | |
96 | #include <libgcc_s.h> | |
97 | ||
98 | +static void *libgcc_s_handle; | |
99 | static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); | |
100 | static _Unwind_Reason_Code (*libgcc_s_personality) | |
101 | (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, | |
102 | @@ -42,13 +45,32 @@ init (void) | |
103 | ||
104 | libgcc_s_resume = resume; | |
105 | libgcc_s_personality = personality; | |
106 | + atomic_write_barrier (); | |
107 | + /* At the point at which any thread writes the handle | |
108 | + to libgcc_s_handle, the initialization is complete. | |
109 | + The writing of libgcc_s_handle is atomic. All other | |
110 | + threads reading libgcc_s_handle do so atomically. Any | |
111 | + thread that does not execute this function must issue | |
112 | + a read barrier to ensure that all of the above has | |
113 | + actually completed and that the values of the | |
114 | + function pointers are correct. */ | |
115 | + libgcc_s_handle = handle; | |
116 | } | |
117 | ||
118 | +static __always_inline void | |
119 | +_maybe_init (void) | |
120 | +{ | |
121 | + if (__builtin_expect (libgcc_s_handle == NULL, 0)) | |
122 | + init (); | |
123 | + else | |
124 | + atomic_read_barrier (); | |
125 | +} | |
126 | + | |
127 | + | |
128 | void | |
129 | _Unwind_Resume (struct _Unwind_Exception *exc) | |
130 | { | |
131 | - if (__builtin_expect (libgcc_s_resume == NULL, 0)) | |
132 | - init (); | |
133 | + _maybe_init (); | |
134 | libgcc_s_resume (exc); | |
135 | } | |
136 | ||
137 | @@ -58,8 +80,7 @@ __gcc_personality_v0 (int version, _Unwi | |
138 | struct _Unwind_Exception *ue_header, | |
139 | struct _Unwind_Context *context) | |
140 | { | |
141 | - if (__builtin_expect (libgcc_s_personality == NULL, 0)) | |
142 | - init (); | |
143 | + _maybe_init (); | |
144 | return libgcc_s_personality (version, actions, exception_class, | |
145 | ue_header, context); | |
146 | } |