[llvm] r369064 - [Support] Re-introduce the RWMutexImpl for macOS < 10.12

Jonas Devlieghere via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 15 16:07:20 PDT 2019


Author: jdevlieghere
Date: Thu Aug 15 16:07:20 2019
New Revision: 369064

URL: http://llvm.org/viewvc/llvm-project?rev=369064&view=rev
Log:
[Support] Re-introduce the RWMutexImpl for macOS < 10.12

In r369018, Benjamin replaced the custom RWMutex implementation with
their C++14 counterpart. Unfortunately, std::shared_timed_mutex is only
available on macOS 10.12 and later. This prevents LLVM from compiling
even on newer versions of the OS when you have an older deployment
target. This patch reintroduced the old RWMutexImpl but guards it by the
macOS availability macro.

Differential revision: https://reviews.llvm.org/D66313

Added:
    llvm/trunk/lib/Support/RWMutex.cpp
Modified:
    llvm/trunk/include/llvm/Support/RWMutex.h
    llvm/trunk/lib/Support/CMakeLists.txt

Modified: llvm/trunk/include/llvm/Support/RWMutex.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/RWMutex.h?rev=369064&r1=369063&r2=369064&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/RWMutex.h (original)
+++ llvm/trunk/include/llvm/Support/RWMutex.h Thu Aug 15 16:07:20 2019
@@ -19,90 +19,181 @@
 #include <mutex>
 #include <shared_mutex>
 
+// std::shared_timed_mutex is only availble on macOS 10.12 and later.
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) &&                  \
+    defined(__MAC_10_12) &&                                                    \
+    __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < __MAC_10_12
+#define USE_RW_MUTEX_IMPL
+#endif
+
 namespace llvm {
 namespace sys {
 
-    /// SmartMutex - An R/W mutex with a compile time constant parameter that
-    /// indicates whether this mutex should become a no-op when we're not
-    /// running in multithreaded mode.
-    template<bool mt_only>
-    class SmartRWMutex {
-      // shared_mutex (C++17) is more efficient than shared_timed_mutex (C++14)
-      // on Windows and always available on MSVC.
+#if defined(USE_RW_MUTEX_IMPL)
+/// Platform agnostic RWMutex class.
+class RWMutexImpl {
+  /// @name Constructors
+  /// @{
+public:
+  /// Initializes the lock but doesn't acquire it.
+  /// Default Constructor.
+  explicit RWMutexImpl();
+
+  /// @}
+  /// @name Do Not Implement
+  /// @{
+  RWMutexImpl(const RWMutexImpl &original) = delete;
+  RWMutexImpl &operator=(const RWMutexImpl &) = delete;
+  /// @}
+
+  /// Releases and removes the lock
+  /// Destructor
+  ~RWMutexImpl();
+
+  /// @}
+  /// @name Methods
+  /// @{
+public:
+  /// Attempts to unconditionally acquire the lock in reader mode. If the
+  /// lock is held by a writer, this method will wait until it can acquire
+  /// the lock.
+  /// @returns false if any kind of error occurs, true otherwise.
+  /// Unconditionally acquire the lock in reader mode.
+  bool lock_shared();
+
+  /// Attempts to release the lock in reader mode.
+  /// @returns false if any kind of error occurs, true otherwise.
+  /// Unconditionally release the lock in reader mode.
+  bool unlock_shared();
+
+  /// Attempts to unconditionally acquire the lock in reader mode. If the
+  /// lock is held by any readers, this method will wait until it can
+  /// acquire the lock.
+  /// @returns false if any kind of error occurs, true otherwise.
+  /// Unconditionally acquire the lock in writer mode.
+  bool lock();
+
+  /// Attempts to release the lock in writer mode.
+  /// @returns false if any kind of error occurs, true otherwise.
+  /// Unconditionally release the lock in write mode.
+  bool unlock();
+
+  //@}
+  /// @name Platform Dependent Data
+  /// @{
+private:
+#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
+  void *data_ = nullptr; ///< We don't know what the data will be
+#endif
+};
+#endif
+
+/// SmartMutex - An R/W mutex with a compile time constant parameter that
+/// indicates whether this mutex should become a no-op when we're not
+/// running in multithreaded mode.
+template <bool mt_only> class SmartRWMutex {
+  // shared_mutex (C++17) is more efficient than shared_timed_mutex (C++14)
+  // on Windows and always available on MSVC.
 #if defined(_MSC_VER) || __cplusplus > 201402L
-      std::shared_mutex impl;
+  std::shared_mutex impl;
+#else
+#if !defined(USE_RW_MUTEX_IMPL)
+  std::shared_timed_mutex impl;
 #else
-      std::shared_timed_mutex impl;
+  RWMutexImpl impl;
 #endif
-      unsigned readers = 0;
-      unsigned writers = 0;
+#endif
+  unsigned readers = 0;
+  unsigned writers = 0;
 
-    public:
-      bool lock_shared() {
-        if (!mt_only || llvm_is_multithreaded()) {
-          impl.lock_shared();
-          return true;
-        }
-
-        // Single-threaded debugging code.  This would be racy in multithreaded
-        // mode, but provides not sanity checks in single threaded mode.
-        ++readers;
-        return true;
-      }
-
-      bool unlock_shared() {
-        if (!mt_only || llvm_is_multithreaded()) {
-          impl.unlock_shared();
-          return true;
-        }
-
-        // Single-threaded debugging code.  This would be racy in multithreaded
-        // mode, but provides not sanity checks in single threaded mode.
-        assert(readers > 0 && "Reader lock not acquired before release!");
-        --readers;
-        return true;
-      }
-
-      bool lock() {
-        if (!mt_only || llvm_is_multithreaded()) {
-          impl.lock();
-          return true;
-        }
-
-        // Single-threaded debugging code.  This would be racy in multithreaded
-        // mode, but provides not sanity checks in single threaded mode.
-        assert(writers == 0 && "Writer lock already acquired!");
-        ++writers;
-        return true;
-      }
-
-      bool unlock() {
-        if (!mt_only || llvm_is_multithreaded()) {
-          impl.unlock();
-          return true;
-        }
-
-        // Single-threaded debugging code.  This would be racy in multithreaded
-        // mode, but provides not sanity checks in single threaded mode.
-        assert(writers == 1 && "Writer lock not acquired before release!");
-        --writers;
-        return true;
-      }
-    };
-
-    typedef SmartRWMutex<false> RWMutex;
-
-    /// ScopedReader - RAII acquisition of a reader lock
-    template<bool mt_only>
-    using SmartScopedReader = const std::shared_lock<SmartRWMutex<mt_only>>;
-
-    typedef SmartScopedReader<false> ScopedReader;
-
-    /// ScopedWriter - RAII acquisition of a writer lock
-    template<bool mt_only>
-    using SmartScopedWriter = std::lock_guard<SmartRWMutex<mt_only>>;
+public:
+  bool lock_shared() {
+    if (!mt_only || llvm_is_multithreaded()) {
+      impl.lock_shared();
+      return true;
+    }
+
+    // Single-threaded debugging code.  This would be racy in multithreaded
+    // mode, but provides not sanity checks in single threaded mode.
+    ++readers;
+    return true;
+  }
+
+  bool unlock_shared() {
+    if (!mt_only || llvm_is_multithreaded()) {
+      impl.unlock_shared();
+      return true;
+    }
+
+    // Single-threaded debugging code.  This would be racy in multithreaded
+    // mode, but provides not sanity checks in single threaded mode.
+    assert(readers > 0 && "Reader lock not acquired before release!");
+    --readers;
+    return true;
+  }
+
+  bool lock() {
+    if (!mt_only || llvm_is_multithreaded()) {
+      impl.lock();
+      return true;
+    }
+
+    // Single-threaded debugging code.  This would be racy in multithreaded
+    // mode, but provides not sanity checks in single threaded mode.
+    assert(writers == 0 && "Writer lock already acquired!");
+    ++writers;
+    return true;
+  }
+
+  bool unlock() {
+    if (!mt_only || llvm_is_multithreaded()) {
+      impl.unlock();
+      return true;
+    }
+
+    // Single-threaded debugging code.  This would be racy in multithreaded
+    // mode, but provides not sanity checks in single threaded mode.
+    assert(writers == 1 && "Writer lock not acquired before release!");
+    --writers;
+    return true;
+  }
+};
+
+typedef SmartRWMutex<false> RWMutex;
+
+/// ScopedReader - RAII acquisition of a reader lock
+#if !defined(USE_RW_MUTEX_IMPL)
+template <bool mt_only>
+using SmartScopedReader = const std::shared_lock<SmartRWMutex<mt_only>>;
+#else
+template <bool mt_only> struct SmartScopedReader {
+  SmartRWMutex<mt_only> &mutex;
 
-    typedef SmartScopedWriter<false> ScopedWriter;
+  explicit SmartScopedReader(SmartRWMutex<mt_only> &m) : mutex(m) {
+    mutex.lock_shared();
+  }
+
+  ~SmartScopedReader() { mutex.unlock_shared(); }
+};
+#endif
+typedef SmartScopedReader<false> ScopedReader;
+
+/// ScopedWriter - RAII acquisition of a writer lock
+#if !defined(USE_RW_MUTEX_IMPL)
+template <bool mt_only>
+using SmartScopedWriter = std::lock_guard<SmartRWMutex<mt_only>>;
+#else
+template <bool mt_only> struct SmartScopedWriter {
+  SmartRWMutex<mt_only> &mutex;
+
+  explicit SmartScopedWriter(SmartRWMutex<mt_only> &m) : mutex(m) {
+    mutex.lock();
+  }
+
+  ~SmartScopedWriter() { mutex.unlock(); }
+};
+#endif
+typedef SmartScopedWriter<false> ScopedWriter;
 
 } // end namespace sys
 } // end namespace llvm

Modified: llvm/trunk/lib/Support/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CMakeLists.txt?rev=369064&r1=369063&r2=369064&view=diff
==============================================================================
--- llvm/trunk/lib/Support/CMakeLists.txt (original)
+++ llvm/trunk/lib/Support/CMakeLists.txt Thu Aug 15 16:07:20 2019
@@ -173,6 +173,7 @@ add_llvm_library(LLVMSupport
   Path.cpp
   Process.cpp
   Program.cpp
+  RWMutex.cpp
   Signals.cpp
   TargetRegistry.cpp
   ThreadLocal.cpp

Added: llvm/trunk/lib/Support/RWMutex.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/RWMutex.cpp?rev=369064&view=auto
==============================================================================
--- llvm/trunk/lib/Support/RWMutex.cpp (added)
+++ llvm/trunk/lib/Support/RWMutex.cpp Thu Aug 15 16:07:20 2019
@@ -0,0 +1,136 @@
+//===- RWMutex.cpp - Reader/Writer Mutual Exclusion Lock --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the llvm::sys::RWMutex class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/RWMutex.h"
+#include "llvm/Config/config.h"
+
+#if defined(USE_RW_MUTEX_IMPL)
+using namespace llvm;
+using namespace sys;
+
+#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
+// Define all methods as no-ops if threading is explicitly disabled
+
+RWMutexImpl::RWMutexImpl() = default;
+RWMutexImpl::~RWMutexImpl() = default;
+
+bool RWMutexImpl::lock_shared() { return true; }
+bool RWMutexImpl::unlock_shared() { return true; }
+bool RWMutexImpl::lock() { return true; }
+bool RWMutexImpl::unlock() { return true; }
+
+#else
+
+#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_RWLOCK_INIT)
+
+#include <cassert>
+#include <cstdlib>
+#include <pthread.h>
+
+// Construct a RWMutex using pthread calls
+RWMutexImpl::RWMutexImpl()
+{
+  // Declare the pthread_rwlock data structures
+  pthread_rwlock_t* rwlock =
+    static_cast<pthread_rwlock_t*>(safe_malloc(sizeof(pthread_rwlock_t)));
+
+#ifdef __APPLE__
+  // Workaround a bug/mis-feature in Darwin's pthread_rwlock_init.
+  bzero(rwlock, sizeof(pthread_rwlock_t));
+#endif
+
+  // Initialize the rwlock
+  int errorcode = pthread_rwlock_init(rwlock, nullptr);
+  (void)errorcode;
+  assert(errorcode == 0);
+
+  // Assign the data member
+  data_ = rwlock;
+}
+
+// Destruct a RWMutex
+RWMutexImpl::~RWMutexImpl()
+{
+  pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
+  assert(rwlock != nullptr);
+  pthread_rwlock_destroy(rwlock);
+  free(rwlock);
+}
+
+bool
+RWMutexImpl::lock_shared()
+{
+  pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
+  assert(rwlock != nullptr);
+
+  int errorcode = pthread_rwlock_rdlock(rwlock);
+  return errorcode == 0;
+}
+
+bool
+RWMutexImpl::unlock_shared()
+{
+  pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
+  assert(rwlock != nullptr);
+
+  int errorcode = pthread_rwlock_unlock(rwlock);
+  return errorcode == 0;
+}
+
+bool
+RWMutexImpl::lock()
+{
+  pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
+  assert(rwlock != nullptr);
+
+  int errorcode = pthread_rwlock_wrlock(rwlock);
+  return errorcode == 0;
+}
+
+bool
+RWMutexImpl::unlock()
+{
+  pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
+  assert(rwlock != nullptr);
+
+  int errorcode = pthread_rwlock_unlock(rwlock);
+  return errorcode == 0;
+}
+
+#else
+
+RWMutexImpl::RWMutexImpl() : data_(new MutexImpl(false)) { }
+
+RWMutexImpl::~RWMutexImpl() {
+  delete static_cast<MutexImpl *>(data_);
+}
+
+bool RWMutexImpl::lock_shared() {
+  return static_cast<MutexImpl *>(data_)->acquire();
+}
+
+bool RWMutexImpl::unlock_shared() {
+  return static_cast<MutexImpl *>(data_)->release();
+}
+
+bool RWMutexImpl::lock() {
+  return static_cast<MutexImpl *>(data_)->acquire();
+}
+
+bool RWMutexImpl::unlock() {
+  return static_cast<MutexImpl *>(data_)->release();
+}
+
+#endif
+#endif
+#endif




More information about the llvm-commits mailing list