|
7 | 7 | //===----------------------------------------------------------------------===// |
8 | 8 |
|
9 | 9 | #include "__cxxabi_config.h" |
| 10 | +#include "cxxabi.h" |
10 | 11 |
|
11 | | -#include "abort_message.h" |
12 | | -#include <__threading_support> |
13 | | - |
14 | | -#include <stdint.h> |
15 | | -#include <string.h> |
| 12 | +// Tell the implementation that we're building the actual implementation |
| 13 | +// (and not testing it) |
| 14 | +#define BUILDING_CXA_GUARD |
| 15 | +#include "cxa_guard_impl.h" |
16 | 16 |
|
17 | 17 | /* |
18 | 18 | This implementation must be careful to not call code external to this file |
|
24 | 24 | to not be a problem. |
25 | 25 | */ |
26 | 26 |
|
27 | | -namespace __cxxabiv1 |
28 | | -{ |
29 | | - |
30 | | -namespace |
31 | | -{ |
32 | | - |
33 | | -enum InitializationResult { |
34 | | - INIT_COMPLETE, |
35 | | - INIT_NOT_COMPLETE, |
36 | | -}; |
| 27 | +namespace __cxxabiv1 { |
37 | 28 |
|
38 | 29 | #if defined(_LIBCXXABI_GUARD_ABI_ARM) |
39 | | -// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must |
40 | | -// be statically initialized to 0. |
41 | | -typedef uint32_t guard_type; |
| 30 | +using guard_type = uint32_t; |
42 | 31 | #else |
43 | | -typedef uint64_t guard_type; |
44 | | -#endif |
45 | | - |
46 | | -#if !defined(_LIBCXXABI_HAS_NO_THREADS) && defined(__APPLE__) && \ |
47 | | - !defined(_LIBCXXABI_GUARD_ABI_ARM) |
48 | | -// This is a special-case pthread dependency for Mac. We can't pull this |
49 | | -// out into libcxx's threading API (__threading_support) because not all |
50 | | -// supported Mac environments provide this function (in pthread.h). To |
51 | | -// make it possible to build/use libcxx in those environments, we have to |
52 | | -// keep this pthread dependency local to libcxxabi. If there is some |
53 | | -// convenient way to detect precisely when pthread_mach_thread_np is |
54 | | -// available in a given Mac environment, it might still be possible to |
55 | | -// bury this dependency in __threading_support. |
56 | | -#ifndef _LIBCPP_HAS_THREAD_API_PTHREAD |
57 | | -#error "How do I pthread_mach_thread_np()?" |
58 | | -#endif |
59 | | -#define LIBCXXABI_HAS_DEADLOCK_DETECTION |
60 | | -#define LOCK_ID_FOR_THREAD() pthread_mach_thread_np(std::__libcpp_thread_get_current_id()) |
61 | | -typedef uint32_t lock_type; |
62 | | -#else |
63 | | -#define LOCK_ID_FOR_THREAD() true |
64 | | -typedef bool lock_type; |
65 | | -#endif |
66 | | - |
67 | | -enum class OnRelease : char { UNLOCK, UNLOCK_AND_BROADCAST }; |
68 | | - |
69 | | -struct GlobalMutexGuard { |
70 | | - explicit GlobalMutexGuard(const char* calling_func, OnRelease on_release) |
71 | | - : calling_func(calling_func), on_release(on_release) { |
72 | | -#ifndef _LIBCXXABI_HAS_NO_THREADS |
73 | | - if (std::__libcpp_mutex_lock(&guard_mut)) |
74 | | - abort_message("%s failed to acquire mutex", calling_func); |
75 | | -#endif |
76 | | - } |
77 | | - |
78 | | - ~GlobalMutexGuard() { |
79 | | -#ifndef _LIBCXXABI_HAS_NO_THREADS |
80 | | - if (std::__libcpp_mutex_unlock(&guard_mut)) |
81 | | - abort_message("%s failed to release mutex", calling_func); |
82 | | - if (on_release == OnRelease::UNLOCK_AND_BROADCAST) { |
83 | | - if (std::__libcpp_condvar_broadcast(&guard_cv)) |
84 | | - abort_message("%s failed to broadcast condition variable", |
85 | | - calling_func); |
86 | | - } |
87 | | -#endif |
88 | | - } |
89 | | - |
90 | | - void wait_for_signal() { |
91 | | -#ifndef _LIBCXXABI_HAS_NO_THREADS |
92 | | - if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut)) |
93 | | - abort_message("%s condition variable wait failed", calling_func); |
94 | | -#endif |
95 | | - } |
96 | | - |
97 | | -private: |
98 | | - GlobalMutexGuard(GlobalMutexGuard const&) = delete; |
99 | | - GlobalMutexGuard& operator=(GlobalMutexGuard const&) = delete; |
100 | | - |
101 | | - const char* const calling_func; |
102 | | - OnRelease on_release; |
103 | | - |
104 | | -#ifndef _LIBCXXABI_HAS_NO_THREADS |
105 | | - static std::__libcpp_mutex_t guard_mut; |
106 | | - static std::__libcpp_condvar_t guard_cv; |
| 32 | +using guard_type = uint64_t; |
107 | 33 | #endif |
108 | | -}; |
109 | | - |
110 | | -#ifndef _LIBCXXABI_HAS_NO_THREADS |
111 | | -std::__libcpp_mutex_t GlobalMutexGuard::guard_mut = _LIBCPP_MUTEX_INITIALIZER; |
112 | | -std::__libcpp_condvar_t GlobalMutexGuard::guard_cv = |
113 | | - _LIBCPP_CONDVAR_INITIALIZER; |
114 | | -#endif |
115 | | - |
116 | | -struct GuardObject; |
117 | | - |
118 | | -/// GuardValue - An abstraction for accessing the various fields and bits of |
119 | | -/// the guard object. |
120 | | -struct GuardValue { |
121 | | -private: |
122 | | - explicit GuardValue(guard_type v) : value(v) {} |
123 | | - friend struct GuardObject; |
124 | | - |
125 | | -public: |
126 | | - /// Functions returning the values used to represent the uninitialized, |
127 | | - /// initialized, and initialization pending states. |
128 | | - static GuardValue ZERO(); |
129 | | - static GuardValue INIT_COMPLETE(); |
130 | | - static GuardValue INIT_PENDING(); |
131 | | - |
132 | | - /// Returns true if the guard value represents that the initialization is |
133 | | - /// complete. |
134 | | - bool is_initialization_complete() const; |
135 | | - |
136 | | - /// Returns true if the guard value represents that the initialization is |
137 | | - /// currently pending. |
138 | | - bool is_initialization_pending() const; |
139 | | - |
140 | | - /// Returns the lock value for the current guard value. |
141 | | - lock_type get_lock_value() const; |
142 | | - |
143 | | -private: |
144 | | - // Returns a guard object corresponding to the specified lock value. |
145 | | - static guard_type guard_value_from_lock(lock_type l); |
146 | | - |
147 | | - // Returns the lock value represented by the specified guard object. |
148 | | - static lock_type lock_value_from_guard(guard_type g); |
149 | | - |
150 | | -private: |
151 | | - guard_type value; |
152 | | -}; |
153 | | - |
154 | | -/// GuardObject - Manages correctly reading and writing to the guard object. |
155 | | -struct GuardObject { |
156 | | - explicit GuardObject(guard_type *g) : guard(g) {} |
157 | | - |
158 | | - // Read the current value of the guard object. |
159 | | - // TODO: Make this read atomic. |
160 | | - GuardValue read() const; |
161 | | - |
162 | | - // Write the specified value to the guard object. |
163 | | - // TODO: Make this atomic |
164 | | - void write(GuardValue new_val); |
165 | | - |
166 | | -private: |
167 | | - GuardObject(const GuardObject&) = delete; |
168 | | - GuardObject& operator=(const GuardObject&) = delete; |
169 | | - |
170 | | - guard_type *guard; |
171 | | -}; |
172 | | - |
173 | | -} // unnamed namespace |
174 | 34 |
|
175 | 35 | extern "C" |
176 | 36 | { |
177 | | - |
178 | 37 | _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type* raw_guard_object) { |
179 | | - GlobalMutexGuard gmutex("__cxa_guard_acquire", OnRelease::UNLOCK); |
180 | | - GuardObject guard(raw_guard_object); |
181 | | - GuardValue current_value = guard.read(); |
182 | | - |
183 | | - if (current_value.is_initialization_complete()) |
184 | | - return INIT_COMPLETE; |
185 | | - |
186 | | - const GuardValue LOCK_ID = GuardValue::INIT_PENDING(); |
187 | | -#ifdef LIBCXXABI_HAS_DEADLOCK_DETECTION |
188 | | - if (current_value.is_initialization_pending() && |
189 | | - current_value.get_lock_value() == LOCK_ID.get_lock_value()) { |
190 | | - abort_message("__cxa_guard_acquire detected deadlock"); |
191 | | - } |
192 | | -#endif |
193 | | - while (current_value.is_initialization_pending()) { |
194 | | - gmutex.wait_for_signal(); |
195 | | - current_value = guard.read(); |
196 | | - } |
197 | | - if (current_value.is_initialization_complete()) |
198 | | - return INIT_COMPLETE; |
199 | | - |
200 | | - guard.write(LOCK_ID); |
201 | | - return INIT_NOT_COMPLETE; |
| 38 | + SelectedImplementation imp(raw_guard_object); |
| 39 | + return static_cast<int>(imp.cxa_guard_acquire()); |
202 | 40 | } |
203 | 41 |
|
204 | 42 | _LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *raw_guard_object) { |
205 | | - GlobalMutexGuard gmutex("__cxa_guard_release", |
206 | | - OnRelease::UNLOCK_AND_BROADCAST); |
207 | | - GuardObject guard(raw_guard_object); |
208 | | - guard.write(GuardValue::ZERO()); |
209 | | - guard.write(GuardValue::INIT_COMPLETE()); |
| 43 | + SelectedImplementation imp(raw_guard_object); |
| 44 | + imp.cxa_guard_release(); |
210 | 45 | } |
211 | 46 |
|
212 | 47 | _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *raw_guard_object) { |
213 | | - GlobalMutexGuard gmutex("__cxa_guard_abort", OnRelease::UNLOCK_AND_BROADCAST); |
214 | | - GuardObject guard(raw_guard_object); |
215 | | - guard.write(GuardValue::ZERO()); |
| 48 | + SelectedImplementation imp(raw_guard_object); |
| 49 | + imp.cxa_guard_abort(); |
216 | 50 | } |
217 | 51 | } // extern "C" |
218 | 52 |
|
219 | | -//===----------------------------------------------------------------------===// |
220 | | -// GuardObject Definitions |
221 | | -//===----------------------------------------------------------------------===// |
222 | | - |
223 | | -GuardValue GuardObject::read() const { |
224 | | - // FIXME: Make this atomic |
225 | | - guard_type val = *guard; |
226 | | - return GuardValue(val); |
227 | | -} |
228 | | - |
229 | | -void GuardObject::write(GuardValue new_val) { |
230 | | - // FIXME: make this atomic |
231 | | - *guard = new_val.value; |
232 | | -} |
233 | | - |
234 | | -//===----------------------------------------------------------------------===// |
235 | | -// GuardValue Definitions |
236 | | -//===----------------------------------------------------------------------===// |
237 | | - |
238 | | -GuardValue GuardValue::ZERO() { return GuardValue(0); } |
239 | | - |
240 | | -GuardValue GuardValue::INIT_COMPLETE() { |
241 | | - guard_type value = {0}; |
242 | | -#if defined(_LIBCXXABI_GUARD_ABI_ARM) |
243 | | - value |= 1; |
244 | | -#else |
245 | | - char* init_bit = (char*)&value; |
246 | | - *init_bit = 1; |
247 | | -#endif |
248 | | - return GuardValue(value); |
249 | | -} |
250 | | - |
251 | | -GuardValue GuardValue::INIT_PENDING() { |
252 | | - return GuardValue(guard_value_from_lock(LOCK_ID_FOR_THREAD())); |
253 | | -} |
254 | | - |
255 | | -bool GuardValue::is_initialization_complete() const { |
256 | | -#if defined(_LIBCXXABI_GUARD_ABI_ARM) |
257 | | - return value & 1; |
258 | | -#else |
259 | | - const char* init_bit = (const char*)&value; |
260 | | - return *init_bit; |
261 | | -#endif |
262 | | -} |
263 | | - |
264 | | -bool GuardValue::is_initialization_pending() const { |
265 | | - return lock_value_from_guard(value) != 0; |
266 | | -} |
267 | | - |
268 | | -lock_type GuardValue::get_lock_value() const { |
269 | | - return lock_value_from_guard(value); |
270 | | -} |
271 | | - |
272 | | -// Create a guard object with the lock set to the specified value. |
273 | | -guard_type GuardValue::guard_value_from_lock(lock_type l) { |
274 | | -#if defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) |
275 | | -#if __LITTLE_ENDIAN__ |
276 | | - return static_cast<guard_type>(l) << 32; |
277 | | -#else |
278 | | - return static_cast<guard_type>(l); |
279 | | -#endif |
280 | | -#else // defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) |
281 | | - guard_type f = {0}; |
282 | | - memcpy(static_cast<char*>(static_cast<void*>(&f)) + 1, &l, sizeof(lock_type)); |
283 | | - return f; |
284 | | -#endif // defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) |
285 | | -} |
286 | | - |
287 | | -lock_type GuardValue::lock_value_from_guard(guard_type g) { |
288 | | -#if defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) |
289 | | -#if __LITTLE_ENDIAN__ |
290 | | - return static_cast<lock_type>(g >> 32); |
291 | | -#else |
292 | | - return static_cast<lock_type>(g); |
293 | | -#endif |
294 | | -#else // defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) |
295 | | - uint8_t guard_bytes[sizeof(guard_type)]; |
296 | | - memcpy(&guard_bytes, &g, sizeof(guard_type)); |
297 | | - return guard_bytes[1] != 0; |
298 | | -#endif // defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) |
299 | | -} |
300 | | - |
301 | 53 | } // __cxxabiv1 |
0 commit comments