blob: f4c2a184dc535e3b62b9297e350fda2c6d2b75f8 [file] [log] [blame]
Howard Hinnant92827182011-05-24 22:01:16 +00001//===---------------------------- cxa_guard.cpp ---------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Saleem Abdulrasoolb4ec5792015-12-04 02:14:58 +000010#include "__cxxabi_config.h"
11
Nick Kledzik41683112011-08-02 01:18:14 +000012#include "abort_message.h"
Asiri Rathnayake71ba2872017-01-03 12:58:34 +000013#include <__threading_support>
Howard Hinnant92827182011-05-24 22:01:16 +000014
Howard Hinnant92827182011-05-24 22:01:16 +000015#include <stdint.h>
Howard Hinnantde34b3e2012-01-25 19:02:40 +000016
17/*
18 This implementation must be careful to not call code external to this file
19 which will turn around and try to call __cxa_guard_acquire reentrantly.
20 For this reason, the headers of this file are as restricted as possible.
21 Previous implementations of this code for __APPLE__ have used
Asiri Rathnayake71ba2872017-01-03 12:58:34 +000022 std::__libcpp_mutex_lock and the abort_message utility without problem. This
23 implementation also uses std::__libcpp_condvar_wait which has tested
Asiri Rathnayake51806732016-10-13 15:05:19 +000024 to not be a problem.
Howard Hinnantde34b3e2012-01-25 19:02:40 +000025*/
Howard Hinnant92827182011-05-24 22:01:16 +000026
27namespace __cxxabiv1
28{
29
30namespace
31{
32
Dan Alberta1fce462015-02-05 01:33:15 +000033#ifdef __arm__
Nick Lewyckyd8cfd652011-06-07 18:46:10 +000034// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
35// be statically initialized to 0.
36typedef uint32_t guard_type;
37
Saleem Abdulrasool21a75e72016-08-31 20:29:05 +000038inline void set_initialized(guard_type* guard_object) {
39 *guard_object |= 1;
40}
41#else
42typedef uint64_t guard_type;
43
44void set_initialized(guard_type* guard_object) {
45 char* initialized = (char*)guard_object;
46 *initialized = 1;
47}
48#endif
49
Asiri Rathnayakeb62a4dd2016-09-21 09:09:32 +000050#if defined(_LIBCXXABI_HAS_NO_THREADS) || (defined(__APPLE__) && !defined(__arm__))
Saleem Abdulrasool21a75e72016-08-31 20:29:05 +000051#ifdef __arm__
52
Nick Lewyckyd8cfd652011-06-07 18:46:10 +000053// Test the lowest bit.
54inline bool is_initialized(guard_type* guard_object) {
55 return (*guard_object) & 1;
56}
57
Nick Lewyckyd8cfd652011-06-07 18:46:10 +000058#else
59
Nick Lewyckyd8cfd652011-06-07 18:46:10 +000060bool is_initialized(guard_type* guard_object) {
61 char* initialized = (char*)guard_object;
62 return *initialized;
63}
64
Saleem Abdulrasool21a75e72016-08-31 20:29:05 +000065#endif
Nick Lewyckyd8cfd652011-06-07 18:46:10 +000066#endif
67
Asiri Rathnayakeb62a4dd2016-09-21 09:09:32 +000068#ifndef _LIBCXXABI_HAS_NO_THREADS
Asiri Rathnayake71ba2872017-01-03 12:58:34 +000069std::__libcpp_mutex_t guard_mut = _LIBCPP_MUTEX_INITIALIZER;
70std::__libcpp_condvar_t guard_cv = _LIBCPP_CONDVAR_INITIALIZER;
Jonathan Roelofsc285efa2014-05-06 21:30:56 +000071#endif
Howard Hinnant92827182011-05-24 22:01:16 +000072
Howard Hinnant4d590c32012-03-14 19:39:50 +000073#if defined(__APPLE__) && !defined(__arm__)
Howard Hinnant92827182011-05-24 22:01:16 +000074
75typedef uint32_t lock_type;
76
77#if __LITTLE_ENDIAN__
78
79inline
80lock_type
81get_lock(uint64_t x)
82{
83 return static_cast<lock_type>(x >> 32);
84}
85
86inline
87void
88set_lock(uint64_t& x, lock_type y)
89{
90 x = static_cast<uint64_t>(y) << 32;
91}
92
93#else // __LITTLE_ENDIAN__
94
95inline
96lock_type
97get_lock(uint64_t x)
98{
99 return static_cast<lock_type>(x);
100}
101
102inline
103void
104set_lock(uint64_t& x, lock_type y)
105{
106 x = y;
107}
108
109#endif // __LITTLE_ENDIAN__
110
Howard Hinnantfcd21a12012-03-14 19:30:00 +0000111#else // !__APPLE__ || __arm__
Howard Hinnant92827182011-05-24 22:01:16 +0000112
113typedef bool lock_type;
114
Eric Fiselier9e9cb7b2017-03-04 01:02:35 +0000115#if !defined(__arm__)
116static_assert(std::is_same<guard_type, uint64_t>::value, "");
117
118inline lock_type get_lock(uint64_t x)
Howard Hinnant92827182011-05-24 22:01:16 +0000119{
120 union
121 {
122 uint64_t guard;
123 uint8_t lock[2];
124 } f = {x};
125 return f.lock[1] != 0;
126}
127
Eric Fiselier9e9cb7b2017-03-04 01:02:35 +0000128inline void set_lock(uint64_t& x, lock_type y)
Howard Hinnant92827182011-05-24 22:01:16 +0000129{
130 union
131 {
132 uint64_t guard;
133 uint8_t lock[2];
134 } f = {0};
135 f.lock[1] = y;
136 x = f.guard;
137}
Eric Fiselier9e9cb7b2017-03-04 01:02:35 +0000138#else // defined(__arm__)
139static_assert(std::is_same<guard_type, uint32_t>::value, "");
Howard Hinnant92827182011-05-24 22:01:16 +0000140
Eric Fiselier9e9cb7b2017-03-04 01:02:35 +0000141inline lock_type get_lock(uint32_t x)
Nick Lewyckyd8cfd652011-06-07 18:46:10 +0000142{
143 union
144 {
145 uint32_t guard;
146 uint8_t lock[2];
147 } f = {x};
148 return f.lock[1] != 0;
149}
150
Eric Fiselier9e9cb7b2017-03-04 01:02:35 +0000151inline void set_lock(uint32_t& x, lock_type y)
Nick Lewyckyd8cfd652011-06-07 18:46:10 +0000152{
153 union
154 {
155 uint32_t guard;
156 uint8_t lock[2];
157 } f = {0};
158 f.lock[1] = y;
159 x = f.guard;
160}
161
Eric Fiselier9e9cb7b2017-03-04 01:02:35 +0000162#endif // !defined(__arm__)
163
164#endif // __APPLE__ && !__arm__
Howard Hinnant92827182011-05-24 22:01:16 +0000165
166} // unnamed namespace
167
168extern "C"
169{
170
Asiri Rathnayakeb62a4dd2016-09-21 09:09:32 +0000171#ifndef _LIBCXXABI_HAS_NO_THREADS
Saleem Abdulrasoolb4ec5792015-12-04 02:14:58 +0000172_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
Jonathan Roelofsc8b4d8d2014-05-08 18:48:43 +0000173 char* initialized = (char*)guard_object;
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000174 if (std::__libcpp_mutex_lock(&guard_mut))
Howard Hinnant92827182011-05-24 22:01:16 +0000175 abort_message("__cxa_guard_acquire failed to acquire mutex");
176 int result = *initialized == 0;
177 if (result)
178 {
Howard Hinnant4d590c32012-03-14 19:39:50 +0000179#if defined(__APPLE__) && !defined(__arm__)
Asiri Rathnayakebbc38242017-01-26 10:38:03 +0000180 // This is a special-case pthread dependency for Mac. We can't pull this
181 // out into libcxx's threading API (__threading_support) because not all
182 // supported Mac environments provide this function (in pthread.h). To
183 // make it possible to build/use libcxx in those environments, we have to
184 // keep this pthread dependency local to libcxxabi. If there is some
185 // convenient way to detect precisely when pthread_mach_thread_np is
186 // available in a given Mac environment, it might still be possible to
187 // bury this dependency in __threading_support.
188 #ifdef _LIBCPP_HAS_THREAD_API_PTHREAD
189 const lock_type id = pthread_mach_thread_np(std::__libcpp_thread_get_current_id());
190 #else
191 #error "How do I pthread_mach_thread_np()?"
192 #endif
Howard Hinnant92827182011-05-24 22:01:16 +0000193 lock_type lock = get_lock(*guard_object);
194 if (lock)
195 {
196 // if this thread set lock for this same guard_object, abort
197 if (lock == id)
198 abort_message("__cxa_guard_acquire detected deadlock");
199 do
200 {
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000201 if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut))
Howard Hinnant92827182011-05-24 22:01:16 +0000202 abort_message("__cxa_guard_acquire condition variable wait failed");
203 lock = get_lock(*guard_object);
204 } while (lock);
Nick Lewyckyd8cfd652011-06-07 18:46:10 +0000205 result = !is_initialized(guard_object);
Howard Hinnant92827182011-05-24 22:01:16 +0000206 if (result)
207 set_lock(*guard_object, id);
208 }
209 else
210 set_lock(*guard_object, id);
Howard Hinnantfcd21a12012-03-14 19:30:00 +0000211#else // !__APPLE__ || __arm__
Howard Hinnant92827182011-05-24 22:01:16 +0000212 while (get_lock(*guard_object))
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000213 if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut))
Howard Hinnant92827182011-05-24 22:01:16 +0000214 abort_message("__cxa_guard_acquire condition variable wait failed");
215 result = *initialized == 0;
216 if (result)
217 set_lock(*guard_object, true);
Howard Hinnantfcd21a12012-03-14 19:30:00 +0000218#endif // !__APPLE__ || __arm__
Howard Hinnant92827182011-05-24 22:01:16 +0000219 }
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000220 if (std::__libcpp_mutex_unlock(&guard_mut))
Howard Hinnant92827182011-05-24 22:01:16 +0000221 abort_message("__cxa_guard_acquire failed to release mutex");
222 return result;
223}
224
Saleem Abdulrasoolb4ec5792015-12-04 02:14:58 +0000225_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000226 if (std::__libcpp_mutex_lock(&guard_mut))
Howard Hinnant92827182011-05-24 22:01:16 +0000227 abort_message("__cxa_guard_release failed to acquire mutex");
228 *guard_object = 0;
Nick Lewyckyd8cfd652011-06-07 18:46:10 +0000229 set_initialized(guard_object);
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000230 if (std::__libcpp_mutex_unlock(&guard_mut))
Howard Hinnant92827182011-05-24 22:01:16 +0000231 abort_message("__cxa_guard_release failed to release mutex");
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000232 if (std::__libcpp_condvar_broadcast(&guard_cv))
Howard Hinnant92827182011-05-24 22:01:16 +0000233 abort_message("__cxa_guard_release failed to broadcast condition variable");
234}
235
Saleem Abdulrasoolb4ec5792015-12-04 02:14:58 +0000236_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000237 if (std::__libcpp_mutex_lock(&guard_mut))
Howard Hinnant92827182011-05-24 22:01:16 +0000238 abort_message("__cxa_guard_abort failed to acquire mutex");
239 *guard_object = 0;
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000240 if (std::__libcpp_mutex_unlock(&guard_mut))
Howard Hinnant92827182011-05-24 22:01:16 +0000241 abort_message("__cxa_guard_abort failed to release mutex");
Asiri Rathnayake71ba2872017-01-03 12:58:34 +0000242 if (std::__libcpp_condvar_broadcast(&guard_cv))
Howard Hinnant92827182011-05-24 22:01:16 +0000243 abort_message("__cxa_guard_abort failed to broadcast condition variable");
244}
245
Asiri Rathnayakeb62a4dd2016-09-21 09:09:32 +0000246#else // _LIBCXXABI_HAS_NO_THREADS
247
248_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
249 return !is_initialized(guard_object);
250}
251
252_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
253 *guard_object = 0;
254 set_initialized(guard_object);
255}
256
257_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
258 *guard_object = 0;
259}
260
261#endif // !_LIBCXXABI_HAS_NO_THREADS
Jonathan Roelofsc285efa2014-05-06 21:30:56 +0000262
Howard Hinnant92827182011-05-24 22:01:16 +0000263} // extern "C"
264
265} // __cxxabiv1