blob: 9cd57cbd65a1da5649212908c2095397e7252fd7 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- RWMutex.h - Reader/Writer Mutual Exclusion Lock ----------*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
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
20namespace llvm {
21namespace sys {
22
Andrew Scullcdfcccc2018-10-05 20:58:37 +010023 /// Platform agnostic RWMutex class.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010024 class RWMutexImpl
25 {
26 /// @name Constructors
27 /// @{
28 public:
29
30 /// Initializes the lock but doesn't acquire it.
Andrew Scullcdfcccc2018-10-05 20:58:37 +010031 /// Default Constructor.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010032 explicit RWMutexImpl();
33
34 /// @}
35 /// @name Do Not Implement
36 /// @{
37 RWMutexImpl(const RWMutexImpl & original) = delete;
38 RWMutexImpl &operator=(const RWMutexImpl &) = delete;
39 /// @}
40
41 /// Releases and removes the lock
Andrew Scullcdfcccc2018-10-05 20:58:37 +010042 /// Destructor
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010043 ~RWMutexImpl();
44
45 /// @}
46 /// @name Methods
47 /// @{
48 public:
49
50 /// Attempts to unconditionally acquire the lock in reader mode. If the
51 /// lock is held by a writer, this method will wait until it can acquire
52 /// the lock.
53 /// @returns false if any kind of error occurs, true otherwise.
Andrew Scullcdfcccc2018-10-05 20:58:37 +010054 /// Unconditionally acquire the lock in reader mode.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010055 bool reader_acquire();
56
57 /// Attempts to release the lock in reader mode.
58 /// @returns false if any kind of error occurs, true otherwise.
Andrew Scullcdfcccc2018-10-05 20:58:37 +010059 /// Unconditionally release the lock in reader mode.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010060 bool reader_release();
61
62 /// Attempts to unconditionally acquire the lock in reader mode. If the
63 /// lock is held by any readers, this method will wait until it can
64 /// acquire the lock.
65 /// @returns false if any kind of error occurs, true otherwise.
Andrew Scullcdfcccc2018-10-05 20:58:37 +010066 /// Unconditionally acquire the lock in writer mode.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010067 bool writer_acquire();
68
69 /// Attempts to release the lock in writer mode.
70 /// @returns false if any kind of error occurs, true otherwise.
Andrew Scullcdfcccc2018-10-05 20:58:37 +010071 /// Unconditionally release the lock in write mode.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010072 bool writer_release();
73
74 //@}
75 /// @name Platform Dependent Data
76 /// @{
77 private:
78#if defined(LLVM_ENABLE_THREADS) && LLVM_ENABLE_THREADS != 0
79 void* data_ = nullptr; ///< We don't know what the data will be
80#endif
81 };
82
83 /// SmartMutex - An R/W mutex with a compile time constant parameter that
84 /// indicates whether this mutex should become a no-op when we're not
85 /// running in multithreaded mode.
86 template<bool mt_only>
87 class SmartRWMutex {
88 RWMutexImpl impl;
89 unsigned readers = 0;
90 unsigned writers = 0;
91
92 public:
93 explicit SmartRWMutex() = default;
94 SmartRWMutex(const SmartRWMutex<mt_only> & original) = delete;
95 SmartRWMutex<mt_only> &operator=(const SmartRWMutex<mt_only> &) = delete;
96
97 bool lock_shared() {
98 if (!mt_only || llvm_is_multithreaded())
99 return impl.reader_acquire();
100
101 // Single-threaded debugging code. This would be racy in multithreaded
102 // mode, but provides not sanity checks in single threaded mode.
103 ++readers;
104 return true;
105 }
106
107 bool unlock_shared() {
108 if (!mt_only || llvm_is_multithreaded())
109 return impl.reader_release();
110
111 // Single-threaded debugging code. This would be racy in multithreaded
112 // mode, but provides not sanity checks in single threaded mode.
113 assert(readers > 0 && "Reader lock not acquired before release!");
114 --readers;
115 return true;
116 }
117
118 bool lock() {
119 if (!mt_only || llvm_is_multithreaded())
120 return impl.writer_acquire();
121
122 // Single-threaded debugging code. This would be racy in multithreaded
123 // mode, but provides not sanity checks in single threaded mode.
124 assert(writers == 0 && "Writer lock already acquired!");
125 ++writers;
126 return true;
127 }
128
129 bool unlock() {
130 if (!mt_only || llvm_is_multithreaded())
131 return impl.writer_release();
132
133 // Single-threaded debugging code. This would be racy in multithreaded
134 // mode, but provides not sanity checks in single threaded mode.
135 assert(writers == 1 && "Writer lock not acquired before release!");
136 --writers;
137 return true;
138 }
139 };
140
141 typedef SmartRWMutex<false> RWMutex;
142
143 /// ScopedReader - RAII acquisition of a reader lock
144 template<bool mt_only>
145 struct SmartScopedReader {
146 SmartRWMutex<mt_only>& mutex;
147
148 explicit SmartScopedReader(SmartRWMutex<mt_only>& m) : mutex(m) {
149 mutex.lock_shared();
150 }
151
152 ~SmartScopedReader() {
153 mutex.unlock_shared();
154 }
155 };
156
157 typedef SmartScopedReader<false> ScopedReader;
158
159 /// ScopedWriter - RAII acquisition of a writer lock
160 template<bool mt_only>
161 struct SmartScopedWriter {
162 SmartRWMutex<mt_only>& mutex;
163
164 explicit SmartScopedWriter(SmartRWMutex<mt_only>& m) : mutex(m) {
165 mutex.lock();
166 }
167
168 ~SmartScopedWriter() {
169 mutex.unlock();
170 }
171 };
172
173 typedef SmartScopedWriter<false> ScopedWriter;
174
175} // end namespace sys
176} // end namespace llvm
177
178#endif // LLVM_SUPPORT_RWMUTEX_H