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 acquire the lock in reader mode. Returns immediately. |
67 | /// @returns true on successful lock acquisition, false otherwise. |
68 | bool try_lock_shared(); |
69 | |
70 | /// Attempts to unconditionally acquire the lock in reader mode. If the |
71 | /// lock is held by any readers, this method will wait until it can |
72 | /// acquire the lock. |
73 | /// @returns false if any kind of error occurs, true otherwise. |
74 | /// Unconditionally acquire the lock in writer mode. |
75 | bool lock(); |
76 | |
77 | /// Attempts to release the lock in writer mode. |
78 | /// @returns false if any kind of error occurs, true otherwise. |
79 | /// Unconditionally release the lock in write mode. |
80 | bool unlock(); |
81 | |
82 | /// Attempts to acquire the lock in writer mode. Returns immediately. |
83 | /// @returns true on successful lock acquisition, false otherwise. |
84 | bool try_lock(); |
85 | |
86 | //@} |
87 | /// @name Platform Dependent Data |
88 | /// @{ |
89 | private: |
90 | #if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0 |
91 | void *data_ = nullptr; ///< We don't know what the data will be |
92 | #endif |
93 | }; |
94 | #endif |
95 | |
96 | /// SmartMutex - An R/W mutex with a compile time constant parameter that |
97 | /// indicates whether this mutex should become a no-op when we're not |
98 | /// running in multithreaded mode. |
99 | template <bool mt_only> class SmartRWMutex { |
100 | #if !defined(LLVM_USE_RW_MUTEX_IMPL) |
101 | std::shared_mutex impl; |
102 | #else |
103 | RWMutexImpl impl; |
104 | #endif |
105 | unsigned readers = 0; |
106 | unsigned writers = 0; |
107 | |
108 | public: |
109 | bool lock_shared() { |
110 | if (!mt_only || llvm_is_multithreaded()) { |
111 | impl.lock_shared(); |
112 | return true; |
113 | } |
114 | |
115 | // Single-threaded debugging code. This would be racy in multithreaded |
116 | // mode, but provides not basic checks in single threaded mode. |
117 | ++readers; |
118 | return true; |
119 | } |
120 | |
121 | bool unlock_shared() { |
122 | if (!mt_only || llvm_is_multithreaded()) { |
123 | impl.unlock_shared(); |
124 | return true; |
125 | } |
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(readers > 0 && "Reader lock not acquired before release!" ); |
130 | --readers; |
131 | return true; |
132 | } |
133 | |
134 | bool try_lock_shared() { return impl.try_lock_shared(); } |
135 | |
136 | bool lock() { |
137 | if (!mt_only || llvm_is_multithreaded()) { |
138 | impl.lock(); |
139 | return true; |
140 | } |
141 | |
142 | // Single-threaded debugging code. This would be racy in multithreaded |
143 | // mode, but provides not basic checks in single threaded mode. |
144 | assert(writers == 0 && "Writer lock already acquired!" ); |
145 | ++writers; |
146 | return true; |
147 | } |
148 | |
149 | bool unlock() { |
150 | if (!mt_only || llvm_is_multithreaded()) { |
151 | impl.unlock(); |
152 | return true; |
153 | } |
154 | |
155 | // Single-threaded debugging code. This would be racy in multithreaded |
156 | // mode, but provides not basic checks in single threaded mode. |
157 | assert(writers == 1 && "Writer lock not acquired before release!" ); |
158 | --writers; |
159 | return true; |
160 | } |
161 | |
162 | bool try_lock() { return impl.try_lock(); } |
163 | }; |
164 | |
165 | typedef SmartRWMutex<false> RWMutex; |
166 | |
167 | /// ScopedReader - RAII acquisition of a reader lock |
168 | #if !defined(LLVM_USE_RW_MUTEX_IMPL) |
169 | template <bool mt_only> |
170 | using SmartScopedReader = const std::shared_lock<SmartRWMutex<mt_only>>; |
171 | #else |
172 | template <bool mt_only> struct SmartScopedReader { |
173 | SmartRWMutex<mt_only> &mutex; |
174 | |
175 | explicit SmartScopedReader(SmartRWMutex<mt_only> &m) : mutex(m) { |
176 | mutex.lock_shared(); |
177 | } |
178 | |
179 | ~SmartScopedReader() { mutex.unlock_shared(); } |
180 | }; |
181 | #endif |
182 | typedef SmartScopedReader<false> ScopedReader; |
183 | |
184 | /// ScopedWriter - RAII acquisition of a writer lock |
185 | #if !defined(LLVM_USE_RW_MUTEX_IMPL) |
186 | template <bool mt_only> |
187 | using SmartScopedWriter = std::lock_guard<SmartRWMutex<mt_only>>; |
188 | #else |
189 | template <bool mt_only> struct SmartScopedWriter { |
190 | SmartRWMutex<mt_only> &mutex; |
191 | |
192 | explicit SmartScopedWriter(SmartRWMutex<mt_only> &m) : mutex(m) { |
193 | mutex.lock(); |
194 | } |
195 | |
196 | ~SmartScopedWriter() { mutex.unlock(); } |
197 | }; |
198 | #endif |
199 | typedef SmartScopedWriter<false> ScopedWriter; |
200 | |
201 | } // end namespace sys |
202 | } // end namespace llvm |
203 | |
204 | #endif // LLVM_SUPPORT_RWMUTEX_H |
205 | |