summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2021-06-09 21:17:52 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-06-09 21:17:52 +0000
commite746cace1690aef6602354f7548795ec3a158181 (patch)
treebd7dfcfe740af204abbe8e27c81f052173b89c98
parentf62fab63714c5f6f8b26d49d5d220ecc8c45e01f (diff)
parent42308500ae5e3439e898a03559768603e11d0059 (diff)
downloadlibcxxabi-e746cace1690aef6602354f7548795ec3a158181.tar.gz
Create RAII lock guard for global initialization lock. am: f0dede204c am: 37f4e675ec am: e0db87d67e am: 42308500ae
Original change: https://android-review.googlesource.com/c/platform/external/libcxxabi/+/1727431 Change-Id: I5c14642b7b9490dcc7bc1a4c0539c3ad2c0adbca
-rw-r--r--src/cxa_guard.cpp175
1 files changed, 94 insertions, 81 deletions
diff --git a/src/cxa_guard.cpp b/src/cxa_guard.cpp
index 20b4adc..c00f702 100644
--- a/src/cxa_guard.cpp
+++ b/src/cxa_guard.cpp
@@ -58,9 +58,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
+ 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
-std::__libcpp_mutex_t guard_mut = _LIBCPP_MUTEX_INITIALIZER;
-std::__libcpp_condvar_t guard_cv = _LIBCPP_CONDVAR_INITIALIZER;
+ 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__)
@@ -161,96 +205,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;
-}
-
-_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");
-}
-
-_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");
-}
-
-#else // _LIBCXXABI_HAS_NO_THREADS
-
-_LIBCXXABI_FUNC_VIS int __cxa_guard_acquire(guard_type *guard_object) {
- return !is_initialized(guard_object);
+ 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) {
- *guard_object = 0;
- set_initialized(guard_object);
+ 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) {
- *guard_object = 0;
+ GlobalMutexGuard gmutex("__cxa_guard_abort", OnRelease::UNLOCK);
+ *guard_object = 0;
}
-#endif // !_LIBCXXABI_HAS_NO_THREADS
} // extern "C"