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