| 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 |     /// 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 |       /// 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 |       /// 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 |       /// 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 |       /// 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 |       /// 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 |       /// 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 |  |