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