RWMutex.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. //===- RWMutex.h - Reader/Writer Mutual Exclusion Lock ----------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file declares the llvm::sys::RWMutex class.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #ifndef LLVM_SUPPORT_RWMUTEX_H
  13. #define LLVM_SUPPORT_RWMUTEX_H
  14. #include "llvm/Config/llvm-config.h"
  15. #include "llvm/Support/Threading.h"
  16. #include <cassert>
  17. #include <mutex>
  18. #include <shared_mutex>
  19. // std::shared_timed_mutex is only availble on macOS 10.12 and later.
  20. #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
  21. #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200
  22. #define LLVM_USE_RW_MUTEX_IMPL
  23. #endif
  24. #endif
  25. namespace llvm {
  26. namespace sys {
  27. #if defined(LLVM_USE_RW_MUTEX_IMPL)
  28. /// Platform agnostic RWMutex class.
  29. class RWMutexImpl {
  30. /// @name Constructors
  31. /// @{
  32. public:
  33. /// Initializes the lock but doesn't acquire it.
  34. /// Default Constructor.
  35. explicit RWMutexImpl();
  36. /// @}
  37. /// @name Do Not Implement
  38. /// @{
  39. RWMutexImpl(const RWMutexImpl &original) = delete;
  40. RWMutexImpl &operator=(const RWMutexImpl &) = delete;
  41. /// @}
  42. /// Releases and removes the lock
  43. /// Destructor
  44. ~RWMutexImpl();
  45. /// @}
  46. /// @name Methods
  47. /// @{
  48. public:
  49. /// Attempts to unconditionally acquire the lock in reader mode. If the
  50. /// lock is held by a writer, this method will wait until it can acquire
  51. /// the lock.
  52. /// @returns false if any kind of error occurs, true otherwise.
  53. /// Unconditionally acquire the lock in reader mode.
  54. bool lock_shared();
  55. /// Attempts to release the lock in reader mode.
  56. /// @returns false if any kind of error occurs, true otherwise.
  57. /// Unconditionally release the lock in reader mode.
  58. bool unlock_shared();
  59. /// Attempts to unconditionally acquire the lock in reader mode. If the
  60. /// lock is held by any readers, this method will wait until it can
  61. /// acquire the lock.
  62. /// @returns false if any kind of error occurs, true otherwise.
  63. /// Unconditionally acquire the lock in writer mode.
  64. bool lock();
  65. /// Attempts to release the lock in writer mode.
  66. /// @returns false if any kind of error occurs, true otherwise.
  67. /// Unconditionally release the lock in write mode.
  68. bool unlock();
  69. //@}
  70. /// @name Platform Dependent Data
  71. /// @{
  72. private:
  73. #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
  74. void *data_ = nullptr; ///< We don't know what the data will be
  75. #endif
  76. };
  77. #endif
  78. /// SmartMutex - An R/W mutex with a compile time constant parameter that
  79. /// indicates whether this mutex should become a no-op when we're not
  80. /// running in multithreaded mode.
  81. template <bool mt_only> class SmartRWMutex {
  82. // shared_mutex (C++17) is more efficient than shared_timed_mutex (C++14)
  83. // on Windows and always available on MSVC.
  84. #if defined(_MSC_VER) || __cplusplus > 201402L
  85. std::shared_mutex impl;
  86. #else
  87. #if !defined(LLVM_USE_RW_MUTEX_IMPL)
  88. std::shared_timed_mutex impl;
  89. #else
  90. RWMutexImpl impl;
  91. #endif
  92. #endif
  93. unsigned readers = 0;
  94. unsigned writers = 0;
  95. public:
  96. bool lock_shared() {
  97. if (!mt_only || llvm_is_multithreaded()) {
  98. impl.lock_shared();
  99. return true;
  100. }
  101. // Single-threaded debugging code. This would be racy in multithreaded
  102. // mode, but provides not sanity checks in single threaded mode.
  103. ++readers;
  104. return true;
  105. }
  106. bool unlock_shared() {
  107. if (!mt_only || llvm_is_multithreaded()) {
  108. impl.unlock_shared();
  109. return true;
  110. }
  111. // Single-threaded debugging code. This would be racy in multithreaded
  112. // mode, but provides not sanity checks in single threaded mode.
  113. assert(readers > 0 && "Reader lock not acquired before release!");
  114. --readers;
  115. return true;
  116. }
  117. bool lock() {
  118. if (!mt_only || llvm_is_multithreaded()) {
  119. impl.lock();
  120. return true;
  121. }
  122. // Single-threaded debugging code. This would be racy in multithreaded
  123. // mode, but provides not sanity checks in single threaded mode.
  124. assert(writers == 0 && "Writer lock already acquired!");
  125. ++writers;
  126. return true;
  127. }
  128. bool unlock() {
  129. if (!mt_only || llvm_is_multithreaded()) {
  130. impl.unlock();
  131. return true;
  132. }
  133. // Single-threaded debugging code. This would be racy in multithreaded
  134. // mode, but provides not sanity checks in single threaded mode.
  135. assert(writers == 1 && "Writer lock not acquired before release!");
  136. --writers;
  137. return true;
  138. }
  139. };
  140. typedef SmartRWMutex<false> RWMutex;
  141. /// ScopedReader - RAII acquisition of a reader lock
  142. #if !defined(LLVM_USE_RW_MUTEX_IMPL)
  143. template <bool mt_only>
  144. using SmartScopedReader = const std::shared_lock<SmartRWMutex<mt_only>>;
  145. #else
  146. template <bool mt_only> struct SmartScopedReader {
  147. SmartRWMutex<mt_only> &mutex;
  148. explicit SmartScopedReader(SmartRWMutex<mt_only> &m) : mutex(m) {
  149. mutex.lock_shared();
  150. }
  151. ~SmartScopedReader() { mutex.unlock_shared(); }
  152. };
  153. #endif
  154. typedef SmartScopedReader<false> ScopedReader;
  155. /// ScopedWriter - RAII acquisition of a writer lock
  156. #if !defined(LLVM_USE_RW_MUTEX_IMPL)
  157. template <bool mt_only>
  158. using SmartScopedWriter = std::lock_guard<SmartRWMutex<mt_only>>;
  159. #else
  160. template <bool mt_only> struct SmartScopedWriter {
  161. SmartRWMutex<mt_only> &mutex;
  162. explicit SmartScopedWriter(SmartRWMutex<mt_only> &m) : mutex(m) {
  163. mutex.lock();
  164. }
  165. ~SmartScopedWriter() { mutex.unlock(); }
  166. };
  167. #endif
  168. typedef SmartScopedWriter<false> ScopedWriter;
  169. } // end namespace sys
  170. } // end namespace llvm
  171. #endif // LLVM_SUPPORT_RWMUTEX_H