xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Support/RWMutex.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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:
lock_shared()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 
unlock_shared()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 
try_lock_shared()134   bool try_lock_shared() { return impl.try_lock_shared(); }
135 
lock()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 
unlock()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 
try_lock()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 
SmartScopedReaderSmartScopedReader175   explicit SmartScopedReader(SmartRWMutex<mt_only> &m) : mutex(m) {
176     mutex.lock_shared();
177   }
178 
~SmartScopedReaderSmartScopedReader179   ~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 
SmartScopedWriterSmartScopedWriter192   explicit SmartScopedWriter(SmartRWMutex<mt_only> &m) : mutex(m) {
193     mutex.lock();
194   }
195 
~SmartScopedWriterSmartScopedWriter196   ~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