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