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
21namespace llvm {
22namespace 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