1 //===---------------------------- 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 10 #include "__cxxabi_config.h" 11 12 #include "abort_message.h" 13 #include "config.h" 14 15 #if !LIBCXXABI_HAS_NO_THREADS 16 # include <pthread.h> 17 #endif 18 #include <stdint.h> 19 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 */ 29 30 namespace __cxxabiv1 31 { 32 33 namespace 34 { 35 36 #ifdef __arm__ 37 38 // A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must 39 // be statically initialized to 0. 40 typedef uint32_t guard_type; 41 42 // Test the lowest bit. 43 inline bool is_initialized(guard_type* guard_object) { 44 return (*guard_object) & 1; 45 } 46 47 inline void set_initialized(guard_type* guard_object) { 48 *guard_object |= 1; 49 } 50 51 #else 52 53 typedef uint64_t guard_type; 54 55 bool is_initialized(guard_type* guard_object) { 56 char* initialized = (char*)guard_object; 57 return *initialized; 58 } 59 60 void set_initialized(guard_type* guard_object) { 61 char* initialized = (char*)guard_object; 62 *initialized = 1; 63 } 64 65 #endif 66 67 #if !LIBCXXABI_HAS_NO_THREADS 68 pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER; 69 pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER; 70 #endif 71 72 #if defined(__APPLE__) && !defined(__arm__) 73 74 typedef uint32_t lock_type; 75 76 #if __LITTLE_ENDIAN__ 77 78 inline 79 lock_type 80 get_lock(uint64_t x) 81 { 82 return static_cast<lock_type>(x >> 32); 83 } 84 85 inline 86 void 87 set_lock(uint64_t& x, lock_type y) 88 { 89 x = static_cast<uint64_t>(y) << 32; 90 } 91 92 #else // __LITTLE_ENDIAN__ 93 94 inline 95 lock_type 96 get_lock(uint64_t x) 97 { 98 return static_cast<lock_type>(x); 99 } 100 101 inline 102 void 103 set_lock(uint64_t& x, lock_type y) 104 { 105 x = y; 106 } 107 108 #endif // __LITTLE_ENDIAN__ 109 110 #else // !__APPLE__ || __arm__ 111 112 typedef bool lock_type; 113 114 inline 115 lock_type 116 get_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 126 inline 127 void 128 set_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 139 inline 140 lock_type 141 get_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 151 inline 152 void 153 set_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 164 #endif // __APPLE__ 165 166 } // unnamed namespace 167 168 extern "C" 169 { 170 171 #if LIBCXXABI_HAS_NO_THREADS 172 _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { 173 return !is_initialized(guard_object); 174 } 175 176 _LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) { 177 *guard_object = 0; 178 set_initialized(guard_object); 179 } 180 181 _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) { 182 *guard_object = 0; 183 } 184 185 #else // !LIBCXXABI_HAS_NO_THREADS 186 187 _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) { 188 char* initialized = (char*)guard_object; 189 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 { 194 #if defined(__APPLE__) && !defined(__arm__) 195 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); 208 result = !is_initialized(guard_object); 209 if (result) 210 set_lock(*guard_object, id); 211 } 212 else 213 set_lock(*guard_object, id); 214 #else // !__APPLE__ || __arm__ 215 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); 221 #endif // !__APPLE__ || __arm__ 222 } 223 if (pthread_mutex_unlock(&guard_mut)) 224 abort_message("__cxa_guard_acquire failed to release mutex"); 225 return result; 226 } 227 228 _LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) { 229 if (pthread_mutex_lock(&guard_mut)) 230 abort_message("__cxa_guard_release failed to acquire mutex"); 231 *guard_object = 0; 232 set_initialized(guard_object); 233 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 239 _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) { 240 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 249 #endif // !LIBCXXABI_HAS_NO_THREADS 250 251 } // extern "C" 252 253 } // __cxxabiv1 254