forked from OSchip/llvm-project
Create RAII lock guard for global initialization lock.
This patch is a part of a series of cleanups to cxa_guard.cpp. It should introduce no functionality change. This patch refactors the use of the global mutex and condvar into a RAII lock guard class. This improves correctness (since unlocks can't be forgotten). It also allows the unification of the non-threading and threading implementations. llvm-svn: 357669
This commit is contained in:
parent
690c70de76
commit
f5de7ad211
|
@ -57,9 +57,53 @@ bool is_initialized(guard_type* guard_object) {
|
|||
}
|
||||
#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
|
||||
std::__libcpp_mutex_t guard_mut = _LIBCPP_MUTEX_INITIALIZER;
|
||||
std::__libcpp_condvar_t guard_cv = _LIBCPP_CONDVAR_INITIALIZER;
|
||||
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;
|
||||
#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
|
||||
|
||||
#if defined(__APPLE__) && !defined(__arm__)
|
||||
|
@ -160,96 +204,65 @@ inline void set_lock(uint32_t& x, lock_type y)
|
|||
extern "C"
|
||||
{
|
||||
|
||||
#ifndef _LIBCXXABI_HAS_NO_THREADS
|
||||
_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
|
||||
if (std::__libcpp_mutex_lock(&guard_mut))
|
||||
abort_message("__cxa_guard_acquire failed to acquire mutex");
|
||||
int result = !is_initialized(guard_object);
|
||||
if (result)
|
||||
{
|
||||
#if defined(__APPLE__) && !defined(__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.
|
||||
#ifdef _LIBCPP_HAS_THREAD_API_PTHREAD
|
||||
const lock_type id = pthread_mach_thread_np(std::__libcpp_thread_get_current_id());
|
||||
#else
|
||||
#error "How do I pthread_mach_thread_np()?"
|
||||
#endif
|
||||
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 (std::__libcpp_condvar_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);
|
||||
GlobalMutexGuard gmutex("__cxa_guard_acquire", OnRelease::UNLOCK);
|
||||
int result = !is_initialized(guard_object);
|
||||
if (result) {
|
||||
#if defined(_LIBCXXABI_HAS_NO_THREADS)
|
||||
// nothing to do
|
||||
#elif defined(__APPLE__) && !defined(__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.
|
||||
#ifdef _LIBCPP_HAS_THREAD_API_PTHREAD
|
||||
const lock_type id =
|
||||
pthread_mach_thread_np(std::__libcpp_thread_get_current_id());
|
||||
#else
|
||||
#error "How do I pthread_mach_thread_np()?"
|
||||
#endif
|
||||
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 {
|
||||
gmutex.wait_for_signal();
|
||||
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 (std::__libcpp_condvar_wait(&guard_cv, &guard_mut))
|
||||
abort_message("__cxa_guard_acquire condition variable wait failed");
|
||||
result = !is_initialized(guard_object);
|
||||
if (result)
|
||||
set_lock(*guard_object, true);
|
||||
#endif // !__APPLE__ || __arm__
|
||||
while (get_lock(*guard_object)) {
|
||||
gmutex.wait_for_signal();
|
||||
}
|
||||
if (std::__libcpp_mutex_unlock(&guard_mut))
|
||||
abort_message("__cxa_guard_acquire failed to release mutex");
|
||||
return result;
|
||||
result = !is_initialized(guard_object);
|
||||
if (result)
|
||||
set_lock(*guard_object, true);
|
||||
#endif // !__APPLE__ || __arm__
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
|
||||
if (std::__libcpp_mutex_lock(&guard_mut))
|
||||
abort_message("__cxa_guard_release failed to acquire mutex");
|
||||
*guard_object = 0;
|
||||
set_initialized(guard_object);
|
||||
if (std::__libcpp_mutex_unlock(&guard_mut))
|
||||
abort_message("__cxa_guard_release failed to release mutex");
|
||||
if (std::__libcpp_condvar_broadcast(&guard_cv))
|
||||
abort_message("__cxa_guard_release failed to broadcast condition variable");
|
||||
GlobalMutexGuard gmutex("__cxa_guard_release",
|
||||
OnRelease::UNLOCK_AND_BROADCAST);
|
||||
*guard_object = 0;
|
||||
set_initialized(guard_object);
|
||||
}
|
||||
|
||||
_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
|
||||
if (std::__libcpp_mutex_lock(&guard_mut))
|
||||
abort_message("__cxa_guard_abort failed to acquire mutex");
|
||||
*guard_object = 0;
|
||||
if (std::__libcpp_mutex_unlock(&guard_mut))
|
||||
abort_message("__cxa_guard_abort failed to release mutex");
|
||||
if (std::__libcpp_condvar_broadcast(&guard_cv))
|
||||
abort_message("__cxa_guard_abort failed to broadcast condition variable");
|
||||
GlobalMutexGuard gmutex("__cxa_guard_abort", OnRelease::UNLOCK);
|
||||
*guard_object = 0;
|
||||
}
|
||||
|
||||
#else // _LIBCXXABI_HAS_NO_THREADS
|
||||
|
||||
_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
|
||||
return !is_initialized(guard_object);
|
||||
}
|
||||
|
||||
_LIBCXXABI_FUNC_VIS void __cxa_guard_release(guard_type *guard_object) {
|
||||
*guard_object = 0;
|
||||
set_initialized(guard_object);
|
||||
}
|
||||
|
||||
_LIBCXXABI_FUNC_VIS void __cxa_guard_abort(guard_type *guard_object) {
|
||||
*guard_object = 0;
|
||||
}
|
||||
|
||||
#endif // !_LIBCXXABI_HAS_NO_THREADS
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
|
Loading…
Reference in New Issue