Loading...
Searching...
No Matches
bigRWMutex.h
1//
2// Copyright 2022 Pixar
3//
4// Licensed under the Apache License, Version 2.0 (the "Apache License")
5// with the following modification; you may not use this file except in
6// compliance with the Apache License and the following modification to it:
7// Section 6. Trademarks. is deleted and replaced with:
8//
9// 6. Trademarks. This License does not grant permission to use the trade
10// names, trademarks, service marks, or product names of the Licensor
11// and its affiliates, except as required to comply with Section 4(c) of
12// the License and to reproduce the content of the NOTICE file.
13//
14// You may obtain a copy of the Apache License at
15//
16// http://www.apache.org/licenses/LICENSE-2.0
17//
18// Unless required by applicable law or agreed to in writing, software
19// distributed under the Apache License with the above modification is
20// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21// KIND, either express or implied. See the Apache License for the specific
22// language governing permissions and limitations under the Apache License.
23//
24#ifndef PXR_BASE_TF_BIG_RW_MUTEX_H
25#define PXR_BASE_TF_BIG_RW_MUTEX_H
26
27#include "pxr/pxr.h"
28#include "pxr/base/tf/api.h"
29
30#include "pxr/base/arch/align.h"
31#include "pxr/base/arch/hints.h"
33#include "pxr/base/tf/hash.h"
34#include "pxr/base/tf/spinRWMutex.h"
35
36#include <atomic>
37#include <memory>
38#include <thread>
39
40PXR_NAMESPACE_OPEN_SCOPE
41
70{
71public:
72 // Number of different cache-line-sized lock states.
73 static constexpr unsigned NumStates = 16;
74
75 // Lock states -- 0 means not locked, -1 means locked for write, other
76 // positive values count the number of readers locking this particular lock
77 // state object.
78 static constexpr int NotLocked = 0;
79 static constexpr int WriteLocked = -1;
80
82 TF_API TfBigRWMutex();
83
86 struct ScopedLock {
87
88 // Acquisition states: -1 means not acquired, -2 means acquired for
89 // write (exclusive lock), >= 0 indicates locked for read, and the value
90 // indicates which lock state index the reader has incremented.
91 static constexpr int NotAcquired = -1;
92 static constexpr int WriteAcquired = -2;
93
96 explicit ScopedLock(TfBigRWMutex &m, bool write=true)
97 : _mutex(&m)
98 , _acqState(NotAcquired) {
99 Acquire(write);
100 }
101
103 ScopedLock() : _mutex(nullptr), _acqState(NotAcquired) {}
104
108 Release();
109 }
110
114 void Acquire(TfBigRWMutex &m, bool write=true) {
115 Release();
116 _mutex = &m;
117 Acquire(write);
118 }
119
125 void Acquire(bool write=true) {
126 if (write) {
127 AcquireWrite();
128 }
129 else {
130 AcquireRead();
131 }
132 }
133
136 void Release() {
137 switch (_acqState) {
138 case NotAcquired:
139 break;
140 case WriteAcquired:
141 _ReleaseWrite();
142 break;
143 default:
144 _ReleaseRead();
145 break;
146 };
147 }
148
151 void AcquireRead() {
152 TF_AXIOM(_acqState == NotAcquired);
153 _acqState = _mutex->_AcquireRead(_GetSeed());
154 }
155
159 TF_AXIOM(_acqState == NotAcquired);
160 _mutex->_AcquireWrite();
161 _acqState = WriteAcquired;
162 }
163
171 TF_AXIOM(_acqState >= 0);
172 Release();
173 AcquireWrite();
174 return false;
175 }
176
177 private:
178
179 void _ReleaseRead() {
180 TF_AXIOM(_acqState >= 0);
181 _mutex->_ReleaseRead(_acqState);
182 _acqState = NotAcquired;
183 }
184
185 void _ReleaseWrite() {
186 TF_AXIOM(_acqState == WriteAcquired);
187 _mutex->_ReleaseWrite();
188 _acqState = NotAcquired;
189 }
190
191 // Helper for returning a seed value associated with this lock object.
192 // This helps determine which lock state a read-lock should use.
193 inline int _GetSeed() const {
194 return static_cast<int>(
195 static_cast<unsigned>(TfHash()(this)) >> 8);
196 }
197
198 TfBigRWMutex *_mutex;
199 int _acqState; // NotAcquired (-1), WriteAcquired (-2), otherwise
200 // acquired for read, and index indicates which lock
201 // state we are associated with.
202 };
203
204private:
205
206 // Optimistic read-lock case inlined.
207 inline int _AcquireRead(int seed) {
208 // Determine a lock state index to use.
209 int stateIndex = seed % NumStates;
210 if (ARCH_UNLIKELY(_writerActive) ||
211 !_states[stateIndex].mutex.TryAcquireRead()) {
212 _AcquireReadContended(stateIndex);
213 }
214 return stateIndex;
215 }
216
217 // Contended read-lock helper.
218 TF_API void _AcquireReadContended(int stateIndex);
219
220 void _ReleaseRead(int stateIndex) {
221 _states[stateIndex].mutex.ReleaseRead();
222 }
223
224 TF_API void _AcquireWrite();
225 TF_API void _ReleaseWrite();
226
227 struct _LockState {
228 TfSpinRWMutex mutex;
229 // This padding ensures that \p state instances sit on different cache
230 // lines.
231 char _unused_padding[
233 };
234
235 std::unique_ptr<_LockState []> _states;
236 std::atomic<bool> _writerActive;
237
238};
239
240PXR_NAMESPACE_CLOSE_SCOPE
241
242#endif // PXR_BASE_TF_BIG_RW_MUTEX_H
Provide architecture-specific memory-alignment information.
This class implements a readers-writer mutex and provides a scoped lock utility.
Definition: bigRWMutex.h:70
TF_API TfBigRWMutex()
Construct a mutex, initially unlocked.
A user-extensible hashing mechanism for use with runtime hash tables.
Definition: hash.h:477
This class implements a readers-writer spin lock that emphasizes throughput when there is light conte...
Definition: spinRWMutex.h:68
Stripped down version of diagnostic.h that doesn't define std::string.
#define ARCH_CACHE_LINE_SIZE
The size of a CPU cache line on the current processor architecture in bytes.
Definition: align.h:84
#define TF_AXIOM(cond)
Aborts if the condition cond is not met.
Definition: diagnostic.h:210
Compiler hints.
Scoped lock utility class.
Definition: bigRWMutex.h:86
bool UpgradeToWriter()
Change this lock's acquisition state from a read lock to a write lock.
Definition: bigRWMutex.h:170
void Acquire(bool write=true)
Acquire either a read or write lock on this lock's associated mutex depending on write.
Definition: bigRWMutex.h:125
ScopedLock()
Construct a scoped lock not associated with a mutex.
Definition: bigRWMutex.h:103
ScopedLock(TfBigRWMutex &m, bool write=true)
Construct a scoped lock for mutex m and acquire either a read or a write lock depending on write.
Definition: bigRWMutex.h:96
void Release()
Release the currently required lock on the associated mutex.
Definition: bigRWMutex.h:136
~ScopedLock()
If this scoped lock is acquired for either read or write, Release() it.
Definition: bigRWMutex.h:107
void Acquire(TfBigRWMutex &m, bool write=true)
If the current scoped lock is acquired, Release() it, then associate this lock with m and acquire eit...
Definition: bigRWMutex.h:114
void AcquireWrite()
Acquire a write lock on this lock's associated mutex.
Definition: bigRWMutex.h:158
void AcquireRead()
Acquire a read lock on this lock's associated mutex.
Definition: bigRWMutex.h:151