[libcxx-commits] [libcxxabi] r357669 - Create RAII lock guard for global initialization lock.

Eric Fiselier via libcxx-commits libcxx-commits at lists.llvm.org
Wed Apr 3 19:54:42 PDT 2019


Author: ericwf
Date: Wed Apr  3 19:54:42 2019
New Revision: 357669

URL: http://llvm.org/viewvc/llvm-project?rev=357669&view=rev
Log:
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.

Modified:
    libcxxabi/trunk/src/cxa_guard.cpp

Modified: libcxxabi/trunk/src/cxa_guard.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/cxa_guard.cpp?rev=357669&r1=357668&r2=357669&view=diff
==============================================================================
--- libcxxabi/trunk/src/cxa_guard.cpp (original)
+++ libcxxabi/trunk/src/cxa_guard.cpp Wed Apr  3 19:54:42 2019
@@ -57,9 +57,53 @@ bool is_initialized(guard_type* guard_ob
 }
 #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_t
 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"
 




More information about the libcxx-commits mailing list