blob: 49f83ede593e40be753fbabdff34d3ee92e1d5b2 [file] [log] [blame]
Howard Hinnant4a889712011-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 Abdulrasool12315ed2015-12-04 02:14:58 +000010#include "__cxxabi_config.h"
11
Nick Kledzik49cbb022011-08-02 01:18:14 +000012#include "abort_message.h"
Jonathan Roelofs40e98422014-05-06 21:30:56 +000013#include "config.h"
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +000014#include <__threading_support>
Howard Hinnant4a889712011-05-24 22:01:16 +000015
Howard Hinnant4a889712011-05-24 22:01:16 +000016#include <stdint.h>
Howard Hinnant5d6b9d22012-01-25 19:02:40 +000017
18/*
19 This implementation must be careful to not call code external to this file
20 which will turn around and try to call __cxa_guard_acquire reentrantly.
21 For this reason, the headers of this file are as restricted as possible.
22 Previous implementations of this code for __APPLE__ have used
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +000023 std::__libcpp_mutex_lock and the abort_message utility without problem. This
24 implementation also uses std::__libcpp_condvar_wait which has tested
Asiri Rathnayake6d3ea682016-10-13 15:05:19 +000025 to not be a problem.
Howard Hinnant5d6b9d22012-01-25 19:02:40 +000026*/
Howard Hinnant4a889712011-05-24 22:01:16 +000027
28namespace __cxxabiv1
29{
30
31namespace
32{
33
Dan Albert3bd13ca2015-02-05 01:33:15 +000034#ifdef __arm__
Nick Lewycky69e35a72011-06-07 18:46:10 +000035// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
36// be statically initialized to 0.
37typedef uint32_t guard_type;
38
Saleem Abdulrasool7c470052016-08-31 20:29:05 +000039inline void set_initialized(guard_type* guard_object) {
40 *guard_object |= 1;
41}
42#else
43typedef uint64_t guard_type;
44
45void set_initialized(guard_type* guard_object) {
46 char* initialized = (char*)guard_object;
47 *initialized = 1;
48}
49#endif
50
Asiri Rathnayake7c98baa2016-09-21 09:09:32 +000051#if defined(_LIBCXXABI_HAS_NO_THREADS) || (defined(__APPLE__) && !defined(__arm__))
Saleem Abdulrasool7c470052016-08-31 20:29:05 +000052#ifdef __arm__
53
Nick Lewycky69e35a72011-06-07 18:46:10 +000054// Test the lowest bit.
55inline bool is_initialized(guard_type* guard_object) {
56 return (*guard_object) & 1;
57}
58
Nick Lewycky69e35a72011-06-07 18:46:10 +000059#else
60
Nick Lewycky69e35a72011-06-07 18:46:10 +000061bool is_initialized(guard_type* guard_object) {
62 char* initialized = (char*)guard_object;
63 return *initialized;
64}
65
Saleem Abdulrasool7c470052016-08-31 20:29:05 +000066#endif
Nick Lewycky69e35a72011-06-07 18:46:10 +000067#endif
68
Asiri Rathnayake7c98baa2016-09-21 09:09:32 +000069#ifndef _LIBCXXABI_HAS_NO_THREADS
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +000070std::__libcpp_mutex_t guard_mut = _LIBCPP_MUTEX_INITIALIZER;
71std::__libcpp_condvar_t guard_cv = _LIBCPP_CONDVAR_INITIALIZER;
Jonathan Roelofs40e98422014-05-06 21:30:56 +000072#endif
Howard Hinnant4a889712011-05-24 22:01:16 +000073
Howard Hinnantffa26662012-03-14 19:39:50 +000074#if defined(__APPLE__) && !defined(__arm__)
Howard Hinnant4a889712011-05-24 22:01:16 +000075
76typedef uint32_t lock_type;
77
78#if __LITTLE_ENDIAN__
79
80inline
81lock_type
82get_lock(uint64_t x)
83{
84 return static_cast<lock_type>(x >> 32);
85}
86
87inline
88void
89set_lock(uint64_t& x, lock_type y)
90{
91 x = static_cast<uint64_t>(y) << 32;
92}
93
94#else // __LITTLE_ENDIAN__
95
96inline
97lock_type
98get_lock(uint64_t x)
99{
100 return static_cast<lock_type>(x);
101}
102
103inline
104void
105set_lock(uint64_t& x, lock_type y)
106{
107 x = y;
108}
109
110#endif // __LITTLE_ENDIAN__
111
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000112#else // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000113
114typedef bool lock_type;
115
116inline
117lock_type
118get_lock(uint64_t x)
119{
120 union
121 {
122 uint64_t guard;
123 uint8_t lock[2];
124 } f = {x};
125 return f.lock[1] != 0;
126}
127
128inline
129void
130set_lock(uint64_t& x, lock_type y)
131{
132 union
133 {
134 uint64_t guard;
135 uint8_t lock[2];
136 } f = {0};
137 f.lock[1] = y;
138 x = f.guard;
139}
140
Nick Lewycky69e35a72011-06-07 18:46:10 +0000141inline
142lock_type
143get_lock(uint32_t x)
144{
145 union
146 {
147 uint32_t guard;
148 uint8_t lock[2];
149 } f = {x};
150 return f.lock[1] != 0;
151}
152
153inline
154void
155set_lock(uint32_t& x, lock_type y)
156{
157 union
158 {
159 uint32_t guard;
160 uint8_t lock[2];
161 } f = {0};
162 f.lock[1] = y;
163 x = f.guard;
164}
165
Howard Hinnant4a889712011-05-24 22:01:16 +0000166#endif // __APPLE__
167
168} // unnamed namespace
169
170extern "C"
171{
172
Asiri Rathnayake7c98baa2016-09-21 09:09:32 +0000173#ifndef _LIBCXXABI_HAS_NO_THREADS
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000174_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
Jonathan Roelofsbce1e4d2014-05-08 18:48:43 +0000175 char* initialized = (char*)guard_object;
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +0000176 if (std::__libcpp_mutex_lock(&guard_mut))
Howard Hinnant4a889712011-05-24 22:01:16 +0000177 abort_message("__cxa_guard_acquire failed to acquire mutex");
178 int result = *initialized == 0;
179 if (result)
180 {
Howard Hinnantffa26662012-03-14 19:39:50 +0000181#if defined(__APPLE__) && !defined(__arm__)
Asiri Rathnayake085b6122017-01-26 10:38:03 +0000182 // This is a special-case pthread dependency for Mac. We can't pull this
183 // out into libcxx's threading API (__threading_support) because not all
184 // supported Mac environments provide this function (in pthread.h). To
185 // make it possible to build/use libcxx in those environments, we have to
186 // keep this pthread dependency local to libcxxabi. If there is some
187 // convenient way to detect precisely when pthread_mach_thread_np is
188 // available in a given Mac environment, it might still be possible to
189 // bury this dependency in __threading_support.
190 #ifdef _LIBCPP_HAS_THREAD_API_PTHREAD
191 const lock_type id = pthread_mach_thread_np(std::__libcpp_thread_get_current_id());
192 #else
193 #error "How do I pthread_mach_thread_np()?"
194 #endif
Howard Hinnant4a889712011-05-24 22:01:16 +0000195 lock_type lock = get_lock(*guard_object);
196 if (lock)
197 {
198 // if this thread set lock for this same guard_object, abort
199 if (lock == id)
200 abort_message("__cxa_guard_acquire detected deadlock");
201 do
202 {
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +0000203 if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut))
Howard Hinnant4a889712011-05-24 22:01:16 +0000204 abort_message("__cxa_guard_acquire condition variable wait failed");
205 lock = get_lock(*guard_object);
206 } while (lock);
Nick Lewycky69e35a72011-06-07 18:46:10 +0000207 result = !is_initialized(guard_object);
Howard Hinnant4a889712011-05-24 22:01:16 +0000208 if (result)
209 set_lock(*guard_object, id);
210 }
211 else
212 set_lock(*guard_object, id);
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000213#else // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000214 while (get_lock(*guard_object))
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +0000215 if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut))
Howard Hinnant4a889712011-05-24 22:01:16 +0000216 abort_message("__cxa_guard_acquire condition variable wait failed");
217 result = *initialized == 0;
218 if (result)
219 set_lock(*guard_object, true);
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000220#endif // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000221 }
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +0000222 if (std::__libcpp_mutex_unlock(&guard_mut))
Howard Hinnant4a889712011-05-24 22:01:16 +0000223 abort_message("__cxa_guard_acquire failed to release mutex");
224 return result;
225}
226
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000227_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +0000228 if (std::__libcpp_mutex_lock(&guard_mut))
Howard Hinnant4a889712011-05-24 22:01:16 +0000229 abort_message("__cxa_guard_release failed to acquire mutex");
230 *guard_object = 0;
Nick Lewycky69e35a72011-06-07 18:46:10 +0000231 set_initialized(guard_object);
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +0000232 if (std::__libcpp_mutex_unlock(&guard_mut))
Howard Hinnant4a889712011-05-24 22:01:16 +0000233 abort_message("__cxa_guard_release failed to release mutex");
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +0000234 if (std::__libcpp_condvar_broadcast(&guard_cv))
Howard Hinnant4a889712011-05-24 22:01:16 +0000235 abort_message("__cxa_guard_release failed to broadcast condition variable");
236}
237
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000238_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +0000239 if (std::__libcpp_mutex_lock(&guard_mut))
Howard Hinnant4a889712011-05-24 22:01:16 +0000240 abort_message("__cxa_guard_abort failed to acquire mutex");
241 *guard_object = 0;
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +0000242 if (std::__libcpp_mutex_unlock(&guard_mut))
Howard Hinnant4a889712011-05-24 22:01:16 +0000243 abort_message("__cxa_guard_abort failed to release mutex");
Asiri Rathnayake97ba9fa2017-01-03 12:58:34 +0000244 if (std::__libcpp_condvar_broadcast(&guard_cv))
Howard Hinnant4a889712011-05-24 22:01:16 +0000245 abort_message("__cxa_guard_abort failed to broadcast condition variable");
246}
247
Asiri Rathnayake7c98baa2016-09-21 09:09:32 +0000248#else // _LIBCXXABI_HAS_NO_THREADS
249
250_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
251 return !is_initialized(guard_object);
252}
253
254_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
255 *guard_object = 0;
256 set_initialized(guard_object);
257}
258
259_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
260 *guard_object = 0;
261}
262
263#endif // !_LIBCXXABI_HAS_NO_THREADS
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000264
Howard Hinnant4a889712011-05-24 22:01:16 +0000265} // extern "C"
266
267} // __cxxabiv1