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.h" 11 #include "abort_message.h" 12 13 #include <pthread.h> 14 #include <stdint.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 18 namespace __cxxabiv1 19 { 20 21 namespace 22 { 23 24 #if LIBCXXABI_ARMEABI 25 26 // A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must 27 // be statically initialized to 0. 28 typedef uint32_t guard_type; 29 30 // Test the lowest bit. 31 inline bool is_initialized(guard_type* guard_object) { 32 return (*guard_object) & 1; 33 } 34 35 inline void set_initialized(guard_type* guard_object) { 36 *guard_object |= 1; 37 } 38 39 #else 40 41 typedef uint64_t guard_type; 42 43 bool is_initialized(guard_type* guard_object) { 44 char* initialized = (char*)guard_object; 45 return *initialized; 46 } 47 48 void set_initialized(guard_type* guard_object) { 49 char* initialized = (char*)guard_object; 50 *initialized = 1; 51 } 52 53 #endif 54 55 pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER; 56 pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER; 57 58 #if __APPLE__ 59 60 typedef uint32_t lock_type; 61 62 #if __LITTLE_ENDIAN__ 63 64 inline 65 lock_type 66 get_lock(uint64_t x) 67 { 68 return static_cast<lock_type>(x >> 32); 69 } 70 71 inline 72 void 73 set_lock(uint64_t& x, lock_type y) 74 { 75 x = static_cast<uint64_t>(y) << 32; 76 } 77 78 #else // __LITTLE_ENDIAN__ 79 80 inline 81 lock_type 82 get_lock(uint64_t x) 83 { 84 return static_cast<lock_type>(x); 85 } 86 87 inline 88 void 89 set_lock(uint64_t& x, lock_type y) 90 { 91 x = y; 92 } 93 94 #endif // __LITTLE_ENDIAN__ 95 96 #else // __APPLE__ 97 98 typedef bool lock_type; 99 100 inline 101 lock_type 102 get_lock(uint64_t x) 103 { 104 union 105 { 106 uint64_t guard; 107 uint8_t lock[2]; 108 } f = {x}; 109 return f.lock[1] != 0; 110 } 111 112 inline 113 void 114 set_lock(uint64_t& x, lock_type y) 115 { 116 union 117 { 118 uint64_t guard; 119 uint8_t lock[2]; 120 } f = {0}; 121 f.lock[1] = y; 122 x = f.guard; 123 } 124 125 inline 126 lock_type 127 get_lock(uint32_t x) 128 { 129 union 130 { 131 uint32_t guard; 132 uint8_t lock[2]; 133 } f = {x}; 134 return f.lock[1] != 0; 135 } 136 137 inline 138 void 139 set_lock(uint32_t& x, lock_type y) 140 { 141 union 142 { 143 uint32_t guard; 144 uint8_t lock[2]; 145 } f = {0}; 146 f.lock[1] = y; 147 x = f.guard; 148 } 149 150 #endif // __APPLE__ 151 152 } // unnamed namespace 153 154 extern "C" 155 { 156 157 int __cxa_guard_acquire(guard_type* guard_object) 158 { 159 char* initialized = (char*)guard_object; 160 if (pthread_mutex_lock(&guard_mut)) 161 abort_message("__cxa_guard_acquire failed to acquire mutex"); 162 int result = *initialized == 0; 163 if (result) 164 { 165 #if __APPLE__ 166 const lock_type id = pthread_mach_thread_np(pthread_self()); 167 lock_type lock = get_lock(*guard_object); 168 if (lock) 169 { 170 // if this thread set lock for this same guard_object, abort 171 if (lock == id) 172 abort_message("__cxa_guard_acquire detected deadlock"); 173 do 174 { 175 if (pthread_cond_wait(&guard_cv, &guard_mut)) 176 abort_message("__cxa_guard_acquire condition variable wait failed"); 177 lock = get_lock(*guard_object); 178 } while (lock); 179 result = !is_initialized(guard_object); 180 if (result) 181 set_lock(*guard_object, id); 182 } 183 else 184 set_lock(*guard_object, id); 185 #else // __APPLE__ 186 while (get_lock(*guard_object)) 187 if (pthread_cond_wait(&guard_cv, &guard_mut)) 188 abort_message("__cxa_guard_acquire condition variable wait failed"); 189 result = *initialized == 0; 190 if (result) 191 set_lock(*guard_object, true); 192 #endif // __APPLE__ 193 } 194 if (pthread_mutex_unlock(&guard_mut)) 195 abort_message("__cxa_guard_acquire failed to release mutex"); 196 return result; 197 } 198 199 void __cxa_guard_release(guard_type* guard_object) 200 { 201 if (pthread_mutex_lock(&guard_mut)) 202 abort_message("__cxa_guard_release failed to acquire mutex"); 203 *guard_object = 0; 204 set_initialized(guard_object); 205 if (pthread_mutex_unlock(&guard_mut)) 206 abort_message("__cxa_guard_release failed to release mutex"); 207 if (pthread_cond_broadcast(&guard_cv)) 208 abort_message("__cxa_guard_release failed to broadcast condition variable"); 209 } 210 211 void __cxa_guard_abort(guard_type* guard_object) 212 { 213 if (pthread_mutex_lock(&guard_mut)) 214 abort_message("__cxa_guard_abort failed to acquire mutex"); 215 *guard_object = 0; 216 if (pthread_mutex_unlock(&guard_mut)) 217 abort_message("__cxa_guard_abort failed to release mutex"); 218 if (pthread_cond_broadcast(&guard_cv)) 219 abort_message("__cxa_guard_abort failed to broadcast condition variable"); 220 } 221 222 } // extern "C" 223 224 } // __cxxabiv1 225