blob: 72e868f787e7c57f21877de4dfcf7ff4a263ab09 [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"
Howard Hinnant4a889712011-05-24 22:01:16 +000014
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +000015#if !LIBCXXABI_HAS_NO_THREADS
Jonathan Roelofs40e98422014-05-06 21:30:56 +000016# include <pthread.h>
17#endif
Howard Hinnant4a889712011-05-24 22:01:16 +000018#include <stdint.h>
Howard Hinnant5d6b9d22012-01-25 19:02:40 +000019
20/*
21 This implementation must be careful to not call code external to this file
22 which will turn around and try to call __cxa_guard_acquire reentrantly.
23 For this reason, the headers of this file are as restricted as possible.
24 Previous implementations of this code for __APPLE__ have used
25 pthread_mutex_lock and the abort_message utility without problem. This
26 implementation also uses pthread_cond_wait which has tested to not be a
27 problem.
28*/
Howard Hinnant4a889712011-05-24 22:01:16 +000029
30namespace __cxxabiv1
31{
32
33namespace
34{
35
Dan Albert3bd13ca2015-02-05 01:33:15 +000036#ifdef __arm__
Nick Lewycky69e35a72011-06-07 18:46:10 +000037
38// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
39// be statically initialized to 0.
40typedef uint32_t guard_type;
41
42// Test the lowest bit.
43inline bool is_initialized(guard_type* guard_object) {
44 return (*guard_object) & 1;
45}
46
47inline void set_initialized(guard_type* guard_object) {
48 *guard_object |= 1;
49}
50
51#else
52
53typedef uint64_t guard_type;
54
55bool is_initialized(guard_type* guard_object) {
56 char* initialized = (char*)guard_object;
57 return *initialized;
58}
59
60void set_initialized(guard_type* guard_object) {
61 char* initialized = (char*)guard_object;
62 *initialized = 1;
63}
64
65#endif
66
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +000067#if !LIBCXXABI_HAS_NO_THREADS
Howard Hinnant4a889712011-05-24 22:01:16 +000068pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
69pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER;
Jonathan Roelofs40e98422014-05-06 21:30:56 +000070#endif
Howard Hinnant4a889712011-05-24 22:01:16 +000071
Howard Hinnantffa26662012-03-14 19:39:50 +000072#if defined(__APPLE__) && !defined(__arm__)
Howard Hinnant4a889712011-05-24 22:01:16 +000073
74typedef uint32_t lock_type;
75
76#if __LITTLE_ENDIAN__
77
78inline
79lock_type
80get_lock(uint64_t x)
81{
82 return static_cast<lock_type>(x >> 32);
83}
84
85inline
86void
87set_lock(uint64_t& x, lock_type y)
88{
89 x = static_cast<uint64_t>(y) << 32;
90}
91
92#else // __LITTLE_ENDIAN__
93
94inline
95lock_type
96get_lock(uint64_t x)
97{
98 return static_cast<lock_type>(x);
99}
100
101inline
102void
103set_lock(uint64_t& x, lock_type y)
104{
105 x = y;
106}
107
108#endif // __LITTLE_ENDIAN__
109
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000110#else // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000111
112typedef bool lock_type;
113
114inline
115lock_type
116get_lock(uint64_t x)
117{
118 union
119 {
120 uint64_t guard;
121 uint8_t lock[2];
122 } f = {x};
123 return f.lock[1] != 0;
124}
125
126inline
127void
128set_lock(uint64_t& x, lock_type y)
129{
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}
138
Nick Lewycky69e35a72011-06-07 18:46:10 +0000139inline
140lock_type
141get_lock(uint32_t x)
142{
143 union
144 {
145 uint32_t guard;
146 uint8_t lock[2];
147 } f = {x};
148 return f.lock[1] != 0;
149}
150
151inline
152void
153set_lock(uint32_t& x, lock_type y)
154{
155 union
156 {
157 uint32_t guard;
158 uint8_t lock[2];
159 } f = {0};
160 f.lock[1] = y;
161 x = f.guard;
162}
163
Howard Hinnant4a889712011-05-24 22:01:16 +0000164#endif // __APPLE__
165
166} // unnamed namespace
167
168extern "C"
169{
170
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +0000171#if LIBCXXABI_HAS_NO_THREADS
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000172_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000173 return !is_initialized(guard_object);
174}
175
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000176_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000177 *guard_object = 0;
178 set_initialized(guard_object);
179}
180
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000181_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000182 *guard_object = 0;
183}
184
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +0000185#else // !LIBCXXABI_HAS_NO_THREADS
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000186
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000187_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
Jonathan Roelofsbce1e4d2014-05-08 18:48:43 +0000188 char* initialized = (char*)guard_object;
Howard Hinnant4a889712011-05-24 22:01:16 +0000189 if (pthread_mutex_lock(&guard_mut))
190 abort_message("__cxa_guard_acquire failed to acquire mutex");
191 int result = *initialized == 0;
192 if (result)
193 {
Howard Hinnantffa26662012-03-14 19:39:50 +0000194#if defined(__APPLE__) && !defined(__arm__)
Howard Hinnant4a889712011-05-24 22:01:16 +0000195 const lock_type id = pthread_mach_thread_np(pthread_self());
196 lock_type lock = get_lock(*guard_object);
197 if (lock)
198 {
199 // if this thread set lock for this same guard_object, abort
200 if (lock == id)
201 abort_message("__cxa_guard_acquire detected deadlock");
202 do
203 {
204 if (pthread_cond_wait(&guard_cv, &guard_mut))
205 abort_message("__cxa_guard_acquire condition variable wait failed");
206 lock = get_lock(*guard_object);
207 } while (lock);
Nick Lewycky69e35a72011-06-07 18:46:10 +0000208 result = !is_initialized(guard_object);
Howard Hinnant4a889712011-05-24 22:01:16 +0000209 if (result)
210 set_lock(*guard_object, id);
211 }
212 else
213 set_lock(*guard_object, id);
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000214#else // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000215 while (get_lock(*guard_object))
216 if (pthread_cond_wait(&guard_cv, &guard_mut))
217 abort_message("__cxa_guard_acquire condition variable wait failed");
218 result = *initialized == 0;
219 if (result)
220 set_lock(*guard_object, true);
Howard Hinnantbaae2be2012-03-14 19:30:00 +0000221#endif // !__APPLE__ || __arm__
Howard Hinnant4a889712011-05-24 22:01:16 +0000222 }
223 if (pthread_mutex_unlock(&guard_mut))
224 abort_message("__cxa_guard_acquire failed to release mutex");
225 return result;
226}
227
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000228_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
Howard Hinnant4a889712011-05-24 22:01:16 +0000229 if (pthread_mutex_lock(&guard_mut))
230 abort_message("__cxa_guard_release failed to acquire mutex");
231 *guard_object = 0;
Nick Lewycky69e35a72011-06-07 18:46:10 +0000232 set_initialized(guard_object);
Howard Hinnant4a889712011-05-24 22:01:16 +0000233 if (pthread_mutex_unlock(&guard_mut))
234 abort_message("__cxa_guard_release failed to release mutex");
235 if (pthread_cond_broadcast(&guard_cv))
236 abort_message("__cxa_guard_release failed to broadcast condition variable");
237}
238
Saleem Abdulrasool12315ed2015-12-04 02:14:58 +0000239_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
Howard Hinnant4a889712011-05-24 22:01:16 +0000240 if (pthread_mutex_lock(&guard_mut))
241 abort_message("__cxa_guard_abort failed to acquire mutex");
242 *guard_object = 0;
243 if (pthread_mutex_unlock(&guard_mut))
244 abort_message("__cxa_guard_abort failed to release mutex");
245 if (pthread_cond_broadcast(&guard_cv))
246 abort_message("__cxa_guard_abort failed to broadcast condition variable");
247}
248
Jonathan Roelofs3b7f0852014-09-05 17:46:40 +0000249#endif // !LIBCXXABI_HAS_NO_THREADS
Jonathan Roelofs40e98422014-05-06 21:30:56 +0000250
Howard Hinnant4a889712011-05-24 22:01:16 +0000251} // extern "C"
252
253} // __cxxabiv1