Index: third_party/libc++abi/src/cxa_guard.cpp |
=================================================================== |
--- third_party/libc++abi/src/cxa_guard.cpp (revision 0) |
+++ third_party/libc++abi/src/cxa_guard.cpp (revision 0) |
@@ -0,0 +1,231 @@ |
+//===---------------------------- cxa_guard.cpp ---------------------------===// |
+// |
+// The LLVM Compiler Infrastructure |
+// |
+// This file is dual licensed under the MIT and the University of Illinois Open |
+// Source Licenses. See LICENSE.TXT for details. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+#include "abort_message.h" |
+ |
+#include <pthread.h> |
+#include <stdint.h> |
+ |
+/* |
+ This implementation must be careful to not call code external to this file |
+ which will turn around and try to call __cxa_guard_acquire reentrantly. |
+ For this reason, the headers of this file are as restricted as possible. |
+ Previous implementations of this code for __APPLE__ have used |
+ pthread_mutex_lock and the abort_message utility without problem. This |
+ implementation also uses pthread_cond_wait which has tested to not be a |
+ problem. |
+*/ |
+ |
+namespace __cxxabiv1 |
+{ |
+ |
+namespace |
+{ |
+ |
+#if __arm__ |
+ |
+// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must |
+// be statically initialized to 0. |
+typedef uint32_t guard_type; |
+ |
+// Test the lowest bit. |
+inline bool is_initialized(guard_type* guard_object) { |
+ return (*guard_object) & 1; |
+} |
+ |
+inline void set_initialized(guard_type* guard_object) { |
+ *guard_object |= 1; |
+} |
+ |
+#else |
+ |
+typedef uint64_t guard_type; |
+ |
+bool is_initialized(guard_type* guard_object) { |
+ char* initialized = (char*)guard_object; |
+ return *initialized; |
+} |
+ |
+void set_initialized(guard_type* guard_object) { |
+ char* initialized = (char*)guard_object; |
+ *initialized = 1; |
+} |
+ |
+#endif |
+ |
+pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER; |
+pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER; |
+ |
+#if defined(__APPLE__) && !defined(__arm__) |
+ |
+typedef uint32_t lock_type; |
+ |
+#if __LITTLE_ENDIAN__ |
+ |
+inline |
+lock_type |
+get_lock(uint64_t x) |
+{ |
+ return static_cast<lock_type>(x >> 32); |
+} |
+ |
+inline |
+void |
+set_lock(uint64_t& x, lock_type y) |
+{ |
+ x = static_cast<uint64_t>(y) << 32; |
+} |
+ |
+#else // __LITTLE_ENDIAN__ |
+ |
+inline |
+lock_type |
+get_lock(uint64_t x) |
+{ |
+ return static_cast<lock_type>(x); |
+} |
+ |
+inline |
+void |
+set_lock(uint64_t& x, lock_type y) |
+{ |
+ x = y; |
+} |
+ |
+#endif // __LITTLE_ENDIAN__ |
+ |
+#else // !__APPLE__ || __arm__ |
+ |
+typedef bool lock_type; |
+ |
+inline |
+lock_type |
+get_lock(uint64_t x) |
+{ |
+ union |
+ { |
+ uint64_t guard; |
+ uint8_t lock[2]; |
+ } f = {x}; |
+ return f.lock[1] != 0; |
+} |
+ |
+inline |
+void |
+set_lock(uint64_t& x, lock_type y) |
+{ |
+ union |
+ { |
+ uint64_t guard; |
+ uint8_t lock[2]; |
+ } f = {0}; |
+ f.lock[1] = y; |
+ x = f.guard; |
+} |
+ |
+inline |
+lock_type |
+get_lock(uint32_t x) |
+{ |
+ union |
+ { |
+ uint32_t guard; |
+ uint8_t lock[2]; |
+ } f = {x}; |
+ return f.lock[1] != 0; |
+} |
+ |
+inline |
+void |
+set_lock(uint32_t& x, lock_type y) |
+{ |
+ union |
+ { |
+ uint32_t guard; |
+ uint8_t lock[2]; |
+ } f = {0}; |
+ f.lock[1] = y; |
+ x = f.guard; |
+} |
+ |
+#endif // __APPLE__ |
+ |
+} // unnamed namespace |
+ |
+extern "C" |
+{ |
+ |
+int __cxa_guard_acquire(guard_type* guard_object) |
+{ |
+ char* initialized = (char*)guard_object; |
+ if (pthread_mutex_lock(&guard_mut)) |
+ abort_message("__cxa_guard_acquire failed to acquire mutex"); |
+ int result = *initialized == 0; |
+ if (result) |
+ { |
+#if defined(__APPLE__) && !defined(__arm__) |
+ const lock_type id = pthread_mach_thread_np(pthread_self()); |
+ lock_type lock = get_lock(*guard_object); |
+ if (lock) |
+ { |
+ // if this thread set lock for this same guard_object, abort |
+ if (lock == id) |
+ abort_message("__cxa_guard_acquire detected deadlock"); |
+ do |
+ { |
+ if (pthread_cond_wait(&guard_cv, &guard_mut)) |
+ abort_message("__cxa_guard_acquire condition variable wait failed"); |
+ lock = get_lock(*guard_object); |
+ } while (lock); |
+ result = !is_initialized(guard_object); |
+ if (result) |
+ set_lock(*guard_object, id); |
+ } |
+ else |
+ set_lock(*guard_object, id); |
+#else // !__APPLE__ || __arm__ |
+ while (get_lock(*guard_object)) |
+ if (pthread_cond_wait(&guard_cv, &guard_mut)) |
+ abort_message("__cxa_guard_acquire condition variable wait failed"); |
+ result = *initialized == 0; |
+ if (result) |
+ set_lock(*guard_object, true); |
+#endif // !__APPLE__ || __arm__ |
+ } |
+ if (pthread_mutex_unlock(&guard_mut)) |
+ abort_message("__cxa_guard_acquire failed to release mutex"); |
+ return result; |
+} |
+ |
+void __cxa_guard_release(guard_type* guard_object) |
+{ |
+ if (pthread_mutex_lock(&guard_mut)) |
+ abort_message("__cxa_guard_release failed to acquire mutex"); |
+ *guard_object = 0; |
+ set_initialized(guard_object); |
+ if (pthread_mutex_unlock(&guard_mut)) |
+ abort_message("__cxa_guard_release failed to release mutex"); |
+ if (pthread_cond_broadcast(&guard_cv)) |
+ abort_message("__cxa_guard_release failed to broadcast condition variable"); |
+} |
+ |
+void __cxa_guard_abort(guard_type* guard_object) |
+{ |
+ if (pthread_mutex_lock(&guard_mut)) |
+ abort_message("__cxa_guard_abort failed to acquire mutex"); |
+ *guard_object = 0; |
+ if (pthread_mutex_unlock(&guard_mut)) |
+ abort_message("__cxa_guard_abort failed to release mutex"); |
+ if (pthread_cond_broadcast(&guard_cv)) |
+ abort_message("__cxa_guard_abort failed to broadcast condition variable"); |
+} |
+ |
+} // extern "C" |
+ |
+} // __cxxabiv1 |
Property changes on: third_party/libc++abi/src/cxa_guard.cpp |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |