RWMutex.h 5.8 KB

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