diff options
Diffstat (limited to 'src/cxa_guard.cpp')
-rw-r--r-- | src/cxa_guard.cpp | 276 |
1 files changed, 14 insertions, 262 deletions
diff --git a/src/cxa_guard.cpp b/src/cxa_guard.cpp index 9ae9e70..64e1e59 100644 --- a/src/cxa_guard.cpp +++ b/src/cxa_guard.cpp @@ -8,12 +8,12 @@ //===----------------------------------------------------------------------===// #include "__cxxabi_config.h" +#include "cxxabi.h" -#include "abort_message.h" -#include <__threading_support> - -#include <stdint.h> -#include <string.h> +// Tell the implementation that we're building the actual implementation +// (and not testing it) +#define BUILDING_CXA_GUARD +#include "cxa_guard_impl.h" /* This implementation must be careful to not call code external to this file @@ -25,278 +25,30 @@ to not be a problem. */ -namespace __cxxabiv1 -{ - -namespace -{ - -enum InitializationResult { - INIT_COMPLETE, - INIT_NOT_COMPLETE, -}; +namespace __cxxabiv1 { #if defined(_LIBCXXABI_GUARD_ABI_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; +using guard_type = uint32_t; #else -typedef uint64_t guard_type; -#endif - -#if !defined(_LIBCXXABI_HAS_NO_THREADS) && defined(__APPLE__) && \ - !defined(_LIBCXXABI_GUARD_ABI_ARM) -// This is a special-case pthread dependency for Mac. We can't pull this -// out into libcxx's threading API (__threading_support) because not all -// supported Mac environments provide this function (in pthread.h). To -// make it possible to build/use libcxx in those environments, we have to -// keep this pthread dependency local to libcxxabi. If there is some -// convenient way to detect precisely when pthread_mach_thread_np is -// available in a given Mac environment, it might still be possible to -// bury this dependency in __threading_support. -#ifndef _LIBCPP_HAS_THREAD_API_PTHREAD -#error "How do I pthread_mach_thread_np()?" -#endif -#define LIBCXXABI_HAS_DEADLOCK_DETECTION -#define LOCK_ID_FOR_THREAD() pthread_mach_thread_np(std::__libcpp_thread_get_current_id()) -typedef uint32_t lock_type; -#else -#define LOCK_ID_FOR_THREAD() true -typedef bool lock_type; -#endif - -enum class OnRelease : char { UNLOCK, UNLOCK_AND_BROADCAST }; - -struct GlobalMutexGuard { - explicit GlobalMutexGuard(const char* calling_func, OnRelease on_release) - : calling_func(calling_func), on_release(on_release) { -#ifndef _LIBCXXABI_HAS_NO_THREADS - if (std::__libcpp_mutex_lock(&guard_mut)) - abort_message("%s failed to acquire mutex", calling_func); -#endif - } - - ~GlobalMutexGuard() { -#ifndef _LIBCXXABI_HAS_NO_THREADS - if (std::__libcpp_mutex_unlock(&guard_mut)) - abort_message("%s failed to release mutex", calling_func); - if (on_release == OnRelease::UNLOCK_AND_BROADCAST) { - if (std::__libcpp_condvar_broadcast(&guard_cv)) - abort_message("%s failed to broadcast condition variable", - calling_func); - } -#endif - } - - void wait_for_signal() { -#ifndef _LIBCXXABI_HAS_NO_THREADS - if (std::__libcpp_condvar_wait(&guard_cv, &guard_mut)) - abort_message("%s condition variable wait failed", calling_func); -#endif - } - -private: - GlobalMutexGuard(GlobalMutexGuard const&) = delete; - GlobalMutexGuard& operator=(GlobalMutexGuard const&) = delete; - - const char* const calling_func; - OnRelease on_release; - -#ifndef _LIBCXXABI_HAS_NO_THREADS - static std::__libcpp_mutex_t guard_mut; - static std::__libcpp_condvar_t guard_cv; +using guard_type = uint64_t; #endif -}; - -#ifndef _LIBCXXABI_HAS_NO_THREADS -std::__libcpp_mutex_t GlobalMutexGuard::guard_mut = _LIBCPP_MUTEX_INITIALIZER; -std::__libcpp_condvar_t GlobalMutexGuard::guard_cv = - _LIBCPP_CONDVAR_INITIALIZER; -#endif - -struct GuardObject; - -/// GuardValue - An abstraction for accessing the various fields and bits of -/// the guard object. -struct GuardValue { -private: - explicit GuardValue(guard_type v) : value(v) {} - friend struct GuardObject; - -public: - /// Functions returning the values used to represent the uninitialized, - /// initialized, and initialization pending states. - static GuardValue ZERO(); - static GuardValue INIT_COMPLETE(); - static GuardValue INIT_PENDING(); - - /// Returns true if the guard value represents that the initialization is - /// complete. - bool is_initialization_complete() const; - - /// Returns true if the guard value represents that the initialization is - /// currently pending. - bool is_initialization_pending() const; - - /// Returns the lock value for the current guard value. - lock_type get_lock_value() const; - -private: - // Returns a guard object corresponding to the specified lock value. - static guard_type guard_value_from_lock(lock_type l); - - // Returns the lock value represented by the specified guard object. - static lock_type lock_value_from_guard(guard_type g); - -private: - guard_type value; -}; - -/// GuardObject - Manages correctly reading and writing to the guard object. -struct GuardObject { - explicit GuardObject(guard_type *g) : guard(g) {} - - // Read the current value of the guard object. - // TODO: Make this read atomic. - GuardValue read() const; - - // Write the specified value to the guard object. - // TODO: Make this atomic - void write(GuardValue new_val); - -private: - GuardObject(const GuardObject&) = delete; - GuardObject& operator=(const GuardObject&) = delete; - - guard_type *guard; -}; - -} // unnamed namespace extern "C" { - _LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type* raw_guard_object) { - GlobalMutexGuard gmutex("__cxa_guard_acquire", OnRelease::UNLOCK); - GuardObject guard(raw_guard_object); - GuardValue current_value = guard.read(); - - if (current_value.is_initialization_complete()) - return INIT_COMPLETE; - - const GuardValue LOCK_ID = GuardValue::INIT_PENDING(); -#ifdef LIBCXXABI_HAS_DEADLOCK_DETECTION - if (current_value.is_initialization_pending() && - current_value.get_lock_value() == LOCK_ID.get_lock_value()) { - abort_message("__cxa_guard_acquire detected deadlock"); - } -#endif - while (current_value.is_initialization_pending()) { - gmutex.wait_for_signal(); - current_value = guard.read(); - } - if (current_value.is_initialization_complete()) - return INIT_COMPLETE; - - guard.write(LOCK_ID); - return INIT_NOT_COMPLETE; + SelectedImplementation imp(raw_guard_object); + return static_cast<int>(imp.cxa_guard_acquire()); } _LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *raw_guard_object) { - GlobalMutexGuard gmutex("__cxa_guard_release", - OnRelease::UNLOCK_AND_BROADCAST); - GuardObject guard(raw_guard_object); - guard.write(GuardValue::ZERO()); - guard.write(GuardValue::INIT_COMPLETE()); + SelectedImplementation imp(raw_guard_object); + imp.cxa_guard_release(); } _LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *raw_guard_object) { - GlobalMutexGuard gmutex("__cxa_guard_abort", OnRelease::UNLOCK_AND_BROADCAST); - GuardObject guard(raw_guard_object); - guard.write(GuardValue::ZERO()); + SelectedImplementation imp(raw_guard_object); + imp.cxa_guard_abort(); } } // extern "C" -//===----------------------------------------------------------------------===// -// GuardObject Definitions -//===----------------------------------------------------------------------===// - -GuardValue GuardObject::read() const { - // FIXME: Make this atomic - guard_type val = *guard; - return GuardValue(val); -} - -void GuardObject::write(GuardValue new_val) { - // FIXME: make this atomic - *guard = new_val.value; -} - -//===----------------------------------------------------------------------===// -// GuardValue Definitions -//===----------------------------------------------------------------------===// - -GuardValue GuardValue::ZERO() { return GuardValue(0); } - -GuardValue GuardValue::INIT_COMPLETE() { - guard_type value = {0}; -#if defined(_LIBCXXABI_GUARD_ABI_ARM) - value |= 1; -#else - char* init_bit = (char*)&value; - *init_bit = 1; -#endif - return GuardValue(value); -} - -GuardValue GuardValue::INIT_PENDING() { - return GuardValue(guard_value_from_lock(LOCK_ID_FOR_THREAD())); -} - -bool GuardValue::is_initialization_complete() const { -#if defined(_LIBCXXABI_GUARD_ABI_ARM) - return value & 1; -#else - const char* init_bit = (const char*)&value; - return *init_bit; -#endif -} - -bool GuardValue::is_initialization_pending() const { - return lock_value_from_guard(value) != 0; -} - -lock_type GuardValue::get_lock_value() const { - return lock_value_from_guard(value); -} - -// Create a guard object with the lock set to the specified value. -guard_type GuardValue::guard_value_from_lock(lock_type l) { -#if defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) -#if __LITTLE_ENDIAN__ - return static_cast<guard_type>(l) << 32; -#else - return static_cast<guard_type>(l); -#endif -#else // defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) - guard_type f = {0}; - memcpy(static_cast<char*>(static_cast<void*>(&f)) + 1, &l, sizeof(lock_type)); - return f; -#endif // defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) -} - -lock_type GuardValue::lock_value_from_guard(guard_type g) { -#if defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) -#if __LITTLE_ENDIAN__ - return static_cast<lock_type>(g >> 32); -#else - return static_cast<lock_type>(g); -#endif -#else // defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) - uint8_t guard_bytes[sizeof(guard_type)]; - memcpy(&guard_bytes, &g, sizeof(guard_type)); - return guard_bytes[1] != 0; -#endif // defined(__APPLE__) && !defined(_LIBCXXABI_GUARD_ABI_ARM) -} - } // __cxxabiv1 |