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: |
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 | |
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 | |
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 | |
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 | |
163 | explicit SmartScopedReader(SmartRWMutex<mt_only> &m) : mutex(m) { |
164 | mutex.lock_shared(); |
165 | } |
166 | |
167 | ~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 | |
180 | explicit SmartScopedWriter(SmartRWMutex<mt_only> &m) : mutex(m) { |
181 | mutex.lock(); |
182 | } |
183 | |
184 | ~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 | |