Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qreadwritelock.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#ifndef QREADWRITELOCK_H
6#define QREADWRITELOCK_H
7
8#include <QtCore/qglobal.h>
9#include <QtCore/qdeadlinetimer.h>
10#include <QtCore/qtsan_impl.h>
11
13
14#if QT_CONFIG(thread)
15
16class QReadWriteLockPrivate;
17
18class QBasicReadWriteLock
19{
20public:
21 constexpr QBasicReadWriteLock() = default;
22
23 void lockForRead()
24 {
25 tryLockForReadInternal(QDeadlineTimer::Forever, 0);
26 }
27 bool tryLockForRead()
28 {
29 return tryLockForReadInternal(QDeadlineTimer(), QtTsan::TryLock);
30 }
31 bool tryLockForRead(QDeadlineTimer timeout)
32 {
33 return tryLockForReadInternal(timeout, QtTsan::TryLock);
34 }
35
36 void lockForWrite()
37 {
38 tryLockForWriteInternal(QDeadlineTimer::Forever, 0);
39 }
40 bool tryLockForWrite()
41 {
42 return tryLockForWriteInternal(QDeadlineTimer(), QtTsan::TryLock);
43 }
44 bool tryLockForWrite(QDeadlineTimer timeout)
45 {
46 return tryLockForWriteInternal(timeout, QtTsan::TryLock);
47 }
48
49 void unlock()
50 {
51 unsigned flags = 0;
52 QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
53 quintptr u = quintptr(d);
54 Q_ASSERT_X(u, "QReadWriteLock::unlock()", "Cannot unlock an unlocked lock");
55 if (u & StateLockedForRead)
56 flags |= QtTsan::ReadLock;
57#ifdef QT_BUILDING_UNDER_TSAN
58 else if (u > StateMask && isContendedLockForRead(d))
59 flags |= QtTsan::ReadLock;
60#endif
61
62 QtTsan::mutexPreUnlock(this, flags);
63 if (u > StateMask || !d_ptr.testAndSetRelease(d, nullptr, d))
64 contendedUnlock(d);
65 QtTsan::mutexPostUnlock(this, flags);
66 }
67
68 // std::shared_mutex API:
69 void lock() { lockForWrite(); }
70 void lock_shared() { lockForRead(); }
71 bool try_lock() { return tryLockForWrite(); }
72 bool try_lock_shared() { return tryLockForRead(); }
73 void unlock_shared() { unlock(); }
74
75protected:
76 static constexpr quintptr StateLockedForRead = 0x1;
77 static constexpr quintptr StateLockedForWrite = 0x2;
78 static constexpr quintptr StateMask = StateLockedForRead | StateLockedForWrite;
79 static constexpr quintptr Counter = 0x10;
80
81 Q_ALWAYS_INLINE bool fastTryLockForRead(QReadWriteLockPrivate *&d)
82 {
83 if (d == nullptr) {
84 auto dummyValue = reinterpret_cast<QReadWriteLockPrivate *>(StateLockedForRead);
85 return d_ptr.testAndSetAcquire(nullptr, dummyValue, d);
86 } else if (quintptr u = quintptr(d), v = u + Counter; u & StateLockedForRead) {
87 return d_ptr.testAndSetAcquire(d, reinterpret_cast<QReadWriteLockPrivate *>(v), d);
88 }
89 return false;
90 }
91
92 Q_ALWAYS_INLINE bool tryLockForReadInternal(QDeadlineTimer timeout, unsigned tsanFlags)
93 {
94 tsanFlags |= QtTsan::ReadLock;
95 QtTsan::mutexPreLock(this, tsanFlags);
96
97 QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
98 bool locked = fastTryLockForRead(d);
99 if (!locked)
100 locked = contendedTryLockForRead(timeout, d);
101
102 if (!locked)
103 tsanFlags |= QtTsan::TryLockFailed;
104 QtTsan::mutexPostLock(this, tsanFlags, 0);
105 return locked;
106 }
107
108 Q_ALWAYS_INLINE bool fastTryLockForWrite(QReadWriteLockPrivate *&d)
109 {
110 auto dummyValue = reinterpret_cast<QReadWriteLockPrivate *>(StateLockedForWrite);
111 if (d == nullptr)
112 return d_ptr.testAndSetAcquire(nullptr, dummyValue, d);
113 return false;
114 }
115
116 Q_ALWAYS_INLINE bool tryLockForWriteInternal(QDeadlineTimer timeout, unsigned tsanFlags)
117 {
118 QtTsan::mutexPreLock(this, tsanFlags);
119
120 QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
121 bool locked = fastTryLockForWrite(d);
122 if (!locked)
123 locked = contendedTryLockForWrite(timeout, d);
124
125 if (!locked)
126 tsanFlags |= QtTsan::TryLockFailed;
127 QtTsan::mutexPostLock(this, tsanFlags, 0);
128 return locked;
129 }
130
131 Q_CORE_EXPORT bool contendedTryLockForRead(QDeadlineTimer timeout, void *dd);
132 Q_CORE_EXPORT bool contendedTryLockForWrite(QDeadlineTimer timeout, void *dd);
133 Q_CORE_EXPORT void contendedUnlock(void *dd);
134 Q_CORE_EXPORT bool isContendedLockForRead(const void *dd) Q_DECL_PURE_FUNCTION;
135
136 constexpr QBasicReadWriteLock(QReadWriteLockPrivate *d) noexcept : d_ptr(d)
137 {}
138 Q_DISABLE_COPY(QBasicReadWriteLock)
139 QAtomicPointer<QReadWriteLockPrivate> d_ptr = { nullptr };
140 friend class QReadWriteLockPrivate;
141};
142
143class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock : public QBasicReadWriteLock
144{
145public:
146 enum RecursionMode { NonRecursive, Recursive };
147
148 QT_CORE_INLINE_SINCE(6, 6)
149 explicit QReadWriteLock(RecursionMode recursionMode = NonRecursive);
150 QT_CORE_INLINE_SINCE(6, 6)
151 ~QReadWriteLock();
152
153#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
154 // was: QT_CORE_INLINE_SINCE(6, 6)
155 void lockForRead();
156 bool tryLockForRead();
157#endif
158 QT_CORE_INLINE_SINCE(6, 6)
159 bool tryLockForRead(int timeout);
160#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
161 bool tryLockForRead(QDeadlineTimer timeout = {});
162#endif
163 using QBasicReadWriteLock::tryLockForRead;
164
165#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
166 // was: QT_CORE_INLINE_SINCE(6, 6)
167 void lockForWrite();
168 bool tryLockForWrite();
169#endif
170 QT_CORE_INLINE_SINCE(6, 6)
171 bool tryLockForWrite(int timeout);
172#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
173 bool tryLockForWrite(QDeadlineTimer timeout = {});
174#endif
175 using QBasicReadWriteLock::tryLockForWrite;
176
177#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
178 void unlock();
179#endif
180
181private:
182 QT7_ONLY(Q_CORE_EXPORT)
183 static QReadWriteLockPrivate *initRecursive();
184 QT7_ONLY(Q_CORE_EXPORT)
185 static void destroyRecursive(QReadWriteLockPrivate *);
186};
187
188#if QT_CORE_INLINE_IMPL_SINCE(6, 6)
189QReadWriteLock::QReadWriteLock(RecursionMode recursionMode)
190 : QBasicReadWriteLock(recursionMode == Recursive ? initRecursive() : nullptr)
191{
192}
193
194QReadWriteLock::~QReadWriteLock()
195{
196 if (auto d = d_ptr.loadAcquire())
197 destroyRecursive(d);
198}
199
200bool QReadWriteLock::tryLockForRead(int timeout)
201{
202 return tryLockForRead(QDeadlineTimer(timeout));
203}
204
205bool QReadWriteLock::tryLockForWrite(int timeout)
206{
207 return tryLockForWrite(QDeadlineTimer(timeout));
208}
209#endif // inline since 6.6
210
211#if defined(Q_CC_MSVC)
212#pragma warning( push )
213#pragma warning( disable : 4312 ) // ignoring the warning from /Wp64
214#endif
215
216class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
217{
218public:
219 Q_NODISCARD_CTOR
220 inline QReadLocker(QReadWriteLock *readWriteLock);
221
222 inline ~QReadLocker()
223 { unlock(); }
224
225 inline void unlock()
226 {
227 if (q_val) {
228 if ((q_val & quintptr(1u)) == quintptr(1u)) {
229 q_val &= ~quintptr(1u);
230 readWriteLock()->unlock();
231 }
232 }
233 }
234
235 inline void relock()
236 {
237 if (q_val) {
238 if ((q_val & quintptr(1u)) == quintptr(0u)) {
239 readWriteLock()->lockForRead();
240 q_val |= quintptr(1u);
241 }
242 }
243 }
244
245 inline QReadWriteLock *readWriteLock() const
246 { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
247
248private:
249 Q_DISABLE_COPY(QReadLocker)
250 quintptr q_val;
251};
252
253inline QReadLocker::QReadLocker(QReadWriteLock *areadWriteLock)
254 : q_val(reinterpret_cast<quintptr>(areadWriteLock))
255{
256 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
257 "QReadLocker", "QReadWriteLock pointer is misaligned");
258 relock();
259}
260
261class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
262{
263public:
264 Q_NODISCARD_CTOR
265 inline QWriteLocker(QReadWriteLock *readWriteLock);
266
267 inline ~QWriteLocker()
268 { unlock(); }
269
270 inline void unlock()
271 {
272 if (q_val) {
273 if ((q_val & quintptr(1u)) == quintptr(1u)) {
274 q_val &= ~quintptr(1u);
275 readWriteLock()->unlock();
276 }
277 }
278 }
279
280 inline void relock()
281 {
282 if (q_val) {
283 if ((q_val & quintptr(1u)) == quintptr(0u)) {
284 readWriteLock()->lockForWrite();
285 q_val |= quintptr(1u);
286 }
287 }
288 }
289
290 inline QReadWriteLock *readWriteLock() const
291 { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
292
293
294private:
295 Q_DISABLE_COPY(QWriteLocker)
296 quintptr q_val;
297};
298
299inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock)
300 : q_val(reinterpret_cast<quintptr>(areadWriteLock))
301{
302 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
303 "QWriteLocker", "QReadWriteLock pointer is misaligned");
304 relock();
305}
306
307#if defined(Q_CC_MSVC)
308#pragma warning( pop )
309#endif
310
311#else // QT_CONFIG(thread)
312
313class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock
314{
315public:
316 enum RecursionMode { NonRecursive, Recursive };
317 inline explicit QReadWriteLock(RecursionMode = NonRecursive) noexcept { }
318 inline ~QReadWriteLock() { }
319
320 void lockForRead() noexcept { }
321 bool tryLockForRead() noexcept { return true; }
322 bool tryLockForRead(QDeadlineTimer) noexcept { return true; }
323 bool tryLockForRead(int timeout) noexcept { Q_UNUSED(timeout); return true; }
324
325 void lockForWrite() noexcept { }
326 bool tryLockForWrite() noexcept { return true; }
327 bool tryLockForWrite(QDeadlineTimer) noexcept { return true; }
328 bool tryLockForWrite(int timeout) noexcept { Q_UNUSED(timeout); return true; }
329
330 void unlock() noexcept { }
331
332private:
333 Q_DISABLE_COPY(QReadWriteLock)
334};
335
336class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
337{
338public:
339 Q_NODISCARD_CTOR
340 inline explicit QReadLocker(QReadWriteLock *) noexcept { }
341 inline ~QReadLocker() noexcept { }
342
343 void unlock() noexcept { }
344 void relock() noexcept { }
345 QReadWriteLock *readWriteLock() noexcept { return nullptr; }
346
347private:
348 Q_DISABLE_COPY(QReadLocker)
349};
350
351class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
352{
353public:
354 Q_NODISCARD_CTOR
355 inline explicit QWriteLocker(QReadWriteLock *) noexcept { }
356 inline ~QWriteLocker() noexcept { }
357
358 void unlock() noexcept { }
359 void relock() noexcept { }
360 QReadWriteLock *readWriteLock() noexcept { return nullptr; }
361
362private:
363 Q_DISABLE_COPY(QWriteLocker)
364};
365
366#endif // QT_CONFIG(thread)
367
368QT_END_NAMESPACE
369
370#endif // QREADWRITELOCK_H
Combined button and popup list for selecting options.
static QString appendSlashIfNeeded(const QString &path)