1 //===---------------------------- cxa_guard.cpp ---------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "abort_message.h"
13 #if !LIBCXXABI_SINGLE_THREADED
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
23 pthread_mutex_lock and the abort_message utility without problem. This
24 implementation also uses pthread_cond_wait which has tested to not be a
36 // A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must
37 // be statically initialized to 0.
38 typedef uint32_t guard_type;
40 // Test the lowest bit.
41 inline bool is_initialized(guard_type* guard_object) {
42 return (*guard_object) & 1;
45 inline void set_initialized(guard_type* guard_object) {
51 typedef uint64_t guard_type;
53 bool is_initialized(guard_type* guard_object) {
54 char* initialized = (char*)guard_object;
58 void set_initialized(guard_type* guard_object) {
59 char* initialized = (char*)guard_object;
65 #if !LIBCXXABI_SINGLE_THREADED
66 pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER;
67 pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER;
70 #if defined(__APPLE__) && !defined(__arm__)
72 typedef uint32_t lock_type;
80 return static_cast<lock_type>(x >> 32);
85 set_lock(uint64_t& x, lock_type y)
87 x = static_cast<uint64_t>(y) << 32;
90 #else // __LITTLE_ENDIAN__
96 return static_cast<lock_type>(x);
101 set_lock(uint64_t& x, lock_type y)
106 #endif // __LITTLE_ENDIAN__
108 #else // !__APPLE__ || __arm__
110 typedef bool lock_type;
121 return f.lock[1] != 0;
126 set_lock(uint64_t& x, lock_type y)
146 return f.lock[1] != 0;
151 set_lock(uint32_t& x, lock_type y)
164 } // unnamed namespace
169 #if LIBCXXABI_SINGLE_THREADED
170 int __cxa_guard_acquire(guard_type* guard_object)
172 return !is_initialized(guard_object);
175 void __cxa_guard_release(guard_type* guard_object)
178 set_initialized(guard_object);
181 void __cxa_guard_abort(guard_type* guard_object)
186 #else // !LIBCXXABI_SINGLE_THREADED
188 int __cxa_guard_acquire(guard_type* guard_object)
190 char* initialized = (char*)guard_object;
191 if (pthread_mutex_lock(&guard_mut))
192 abort_message("__cxa_guard_acquire failed to acquire mutex");
193 int result = *initialized == 0;
196 #if defined(__APPLE__) && !defined(__arm__)
197 const lock_type id = pthread_mach_thread_np(pthread_self());
198 lock_type lock = get_lock(*guard_object);
201 // if this thread set lock for this same guard_object, abort
203 abort_message("__cxa_guard_acquire detected deadlock");
206 if (pthread_cond_wait(&guard_cv, &guard_mut))
207 abort_message("__cxa_guard_acquire condition variable wait failed");
208 lock = get_lock(*guard_object);
210 result = !is_initialized(guard_object);
212 set_lock(*guard_object, id);
215 set_lock(*guard_object, id);
216 #else // !__APPLE__ || __arm__
217 while (get_lock(*guard_object))
218 if (pthread_cond_wait(&guard_cv, &guard_mut))
219 abort_message("__cxa_guard_acquire condition variable wait failed");
220 result = *initialized == 0;
222 set_lock(*guard_object, true);
223 #endif // !__APPLE__ || __arm__
225 if (pthread_mutex_unlock(&guard_mut))
226 abort_message("__cxa_guard_acquire failed to release mutex");
230 void __cxa_guard_release(guard_type* guard_object)
232 if (pthread_mutex_lock(&guard_mut))
233 abort_message("__cxa_guard_release failed to acquire mutex");
235 set_initialized(guard_object);
236 if (pthread_mutex_unlock(&guard_mut))
237 abort_message("__cxa_guard_release failed to release mutex");
238 if (pthread_cond_broadcast(&guard_cv))
239 abort_message("__cxa_guard_release failed to broadcast condition variable");
242 void __cxa_guard_abort(guard_type* guard_object)
244 if (pthread_mutex_lock(&guard_mut))
245 abort_message("__cxa_guard_abort failed to acquire mutex");
247 if (pthread_mutex_unlock(&guard_mut))
248 abort_message("__cxa_guard_abort failed to release mutex");
249 if (pthread_cond_broadcast(&guard_cv))
250 abort_message("__cxa_guard_abort failed to broadcast condition variable");
253 #endif // !LIBCXXABI_SINGLE_THREADED