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