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 QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
52 unsigned flags = describeLockForTSan(d);
53 quintptr u = quintptr(d);
54 Q_ASSERT_X(u, "QReadWriteLock::unlock()", "Cannot unlock an unlocked lock");
55
56 QtTsan::mutexPreUnlock(this, flags);
57 if (u > StateMask || !d_ptr.testAndSetRelease(d, nullptr, d))
58 contendedUnlock(d);
59 QtTsan::mutexPostUnlock(this, flags);
60 }
61
62 // std::shared_mutex API:
63 void lock() { lockForWrite(); }
64 void lock_shared() { lockForRead(); }
65 bool try_lock() { return tryLockForWrite(); }
66 bool try_lock_shared() { return tryLockForRead(); }
67 void unlock_shared() { unlock(); }
68
69protected:
70 static constexpr quintptr StateLockedForRead = 0x1;
71 static constexpr quintptr StateLockedForWrite = 0x2;
72 static constexpr quintptr StateMask = StateLockedForRead | StateLockedForWrite;
73 static constexpr quintptr Counter = 0x10;
74
75 Q_ALWAYS_INLINE bool fastTryLockForRead(QReadWriteLockPrivate *&d)
76 {
77 if (d == nullptr) {
78 auto dummyValue = reinterpret_cast<QReadWriteLockPrivate *>(StateLockedForRead);
79 return d_ptr.testAndSetAcquire(nullptr, dummyValue, d);
80 } else if (quintptr u = quintptr(d), v = u + Counter; u & StateLockedForRead) {
81 return d_ptr.testAndSetAcquire(d, reinterpret_cast<QReadWriteLockPrivate *>(v), d);
82 }
83 return false;
84 }
85
86 Q_ALWAYS_INLINE bool tryLockForReadInternal(QDeadlineTimer timeout, unsigned tsanFlags)
87 {
88 tsanFlags |= QtTsan::ReadLock;
89 QtTsan::mutexPreLock(this, tsanFlags);
90
91 QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
92 bool locked = fastTryLockForRead(d);
93 if (!locked)
94 locked = contendedTryLockForRead(timeout, d);
95
96 if (!locked)
97 tsanFlags |= QtTsan::TryLockFailed;
98 QtTsan::mutexPostLock(this, tsanFlags, 0);
99 return locked;
100 }
101
102 Q_ALWAYS_INLINE bool fastTryLockForWrite(QReadWriteLockPrivate *&d)
103 {
104 auto dummyValue = reinterpret_cast<QReadWriteLockPrivate *>(StateLockedForWrite);
105 if (d == nullptr)
106 return d_ptr.testAndSetAcquire(nullptr, dummyValue, d);
107 return false;
108 }
109
110 Q_ALWAYS_INLINE bool tryLockForWriteInternal(QDeadlineTimer timeout, unsigned tsanFlags)
111 {
112 QtTsan::mutexPreLock(this, tsanFlags);
113
114 QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
115 bool locked = fastTryLockForWrite(d);
116 if (!locked)
117 locked = contendedTryLockForWrite(timeout, d);
118
119 if (!locked)
120 tsanFlags |= QtTsan::TryLockFailed;
121 QtTsan::mutexPostLock(this, tsanFlags, 0);
122 return locked;
123 }
124
125 Q_CORE_EXPORT bool contendedTryLockForRead(QDeadlineTimer timeout, void *dd);
126 Q_CORE_EXPORT bool contendedTryLockForWrite(QDeadlineTimer timeout, void *dd);
127 Q_CORE_EXPORT void contendedUnlock(void *dd);
128#if QT_CORE_REMOVED_SINCE(6, 12)
129 Q_CORE_EXPORT bool isContendedLockForRead(const void *dd) Q_DECL_PURE_FUNCTION;
130#endif
131 static Q_CORE_EXPORT quintptr describeLockInternal(void *dd) noexcept Q_DECL_PURE_FUNCTION;
132 static uint describeLockForTSan(const QReadWriteLockPrivate *d, uint flags = 0) noexcept
133 {
134 quintptr u = 0;
135#ifdef QT_BUILDING_UNDER_TSAN
136 u = describeLockInternal(d);
137#else
138 Q_UNUSED(d);
139#endif
140 if (u & StateLockedForRead)
141 flags |= QtTsan::ReadLock;
142 return flags;
143 }
144
145 constexpr QBasicReadWriteLock(QReadWriteLockPrivate *d) noexcept : d_ptr(d)
146 {}
147 Q_DISABLE_COPY(QBasicReadWriteLock)
148 QAtomicPointer<QReadWriteLockPrivate> d_ptr = { nullptr };
149 friend class QReadWriteLockPrivate;
150};
151
152class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock : public QBasicReadWriteLock
153{
154public:
155 enum RecursionMode { NonRecursive, Recursive };
156
157 QT_CORE_INLINE_SINCE(6, 6)
158 explicit QReadWriteLock(RecursionMode recursionMode = NonRecursive);
159 QT_CORE_INLINE_SINCE(6, 6)
160 ~QReadWriteLock();
161
162#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
163 // was: QT_CORE_INLINE_SINCE(6, 6)
164 void lockForRead();
165 bool tryLockForRead();
166#endif
167 QT_CORE_INLINE_SINCE(6, 6)
168 bool tryLockForRead(int timeout);
169#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
170 bool tryLockForRead(QDeadlineTimer timeout = {});
171#endif
172 using QBasicReadWriteLock::tryLockForRead;
173
174#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
175 // was: QT_CORE_INLINE_SINCE(6, 6)
176 void lockForWrite();
177 bool tryLockForWrite();
178#endif
179 QT_CORE_INLINE_SINCE(6, 6)
180 bool tryLockForWrite(int timeout);
181#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
182 bool tryLockForWrite(QDeadlineTimer timeout = {});
183#endif
184 using QBasicReadWriteLock::tryLockForWrite;
185
186#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
187 void unlock();
188#endif
189
190private:
191#if QT_CORE_REMOVED_SINCE(6, 12)
192 static QReadWriteLockPrivate *initRecursive();
193 static void destroyRecursive(QReadWriteLockPrivate *);
194#endif
195
196 QT7_ONLY(Q_CORE_EXPORT) static void *initRecursiveHelper();
197 QT7_ONLY(Q_CORE_EXPORT) static void destroyRecursiveHelper(void *) noexcept;
198 static QReadWriteLockPrivate *initRecursive2()
199 {
200 auto d = static_cast<QReadWriteLockPrivate *>(initRecursiveHelper());
201 Q_PRESUME(quintptr(d) > StateMask);
202#ifdef QT_BUILDING_UNDER_TSAN
203 unsigned flags = __tsan_mutex_write_reentrant | __tsan_mutex_read_reentrant;
204# if (defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1200) || (defined(Q_CC_CLANG) && Q_CC_CLANG >= 1200)
205 flags |= __tsan_mutex_not_static;
206# endif
207 __tsan_mutex_create(d, flags);
208#endif
209 return d;
210 }
211 static void destroyRecursive2(QReadWriteLockPrivate *d)
212 {
213#ifdef QT_BUILDING_UNDER_TSAN
214 unsigned flags = 0;
215 __tsan_mutex_destroy(d, flags);
216#endif
217 destroyRecursiveHelper(d);
218 }
219};
220
221#if QT_CORE_INLINE_IMPL_SINCE(6, 6)
222QReadWriteLock::QReadWriteLock(RecursionMode recursionMode)
223 : QBasicReadWriteLock(recursionMode == Recursive ? initRecursive2() : nullptr)
224{
225}
226
227QReadWriteLock::~QReadWriteLock()
228{
229 if (auto d = d_ptr.loadAcquire())
230 destroyRecursive2(d);
231}
232
233bool QReadWriteLock::tryLockForRead(int timeout)
234{
235 return tryLockForRead(QDeadlineTimer(timeout));
236}
237
238bool QReadWriteLock::tryLockForWrite(int timeout)
239{
240 return tryLockForWrite(QDeadlineTimer(timeout));
241}
242#endif // inline since 6.6
243
244#if defined(Q_CC_MSVC)
245#pragma warning( push )
246#pragma warning( disable : 4312 ) // ignoring the warning from /Wp64
247#endif
248
249class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
250{
251public:
252 Q_NODISCARD_CTOR
253 inline QReadLocker(QReadWriteLock *readWriteLock);
254
255 inline ~QReadLocker()
256 { unlock(); }
257
258 inline void unlock()
259 {
260 if (q_val) {
261 if ((q_val & quintptr(1u)) == quintptr(1u)) {
262 q_val &= ~quintptr(1u);
263 readWriteLock()->unlock();
264 }
265 }
266 }
267
268 inline void relock()
269 {
270 if (q_val) {
271 if ((q_val & quintptr(1u)) == quintptr(0u)) {
272 readWriteLock()->lockForRead();
273 q_val |= quintptr(1u);
274 }
275 }
276 }
277
278 inline QReadWriteLock *readWriteLock() const
279 { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
280
281private:
282 Q_DISABLE_COPY(QReadLocker)
283 quintptr q_val;
284};
285
286inline QReadLocker::QReadLocker(QReadWriteLock *areadWriteLock)
287 : q_val(reinterpret_cast<quintptr>(areadWriteLock))
288{
289 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
290 "QReadLocker", "QReadWriteLock pointer is misaligned");
291 relock();
292}
293
294class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
295{
296public:
297 Q_NODISCARD_CTOR
298 inline QWriteLocker(QReadWriteLock *readWriteLock);
299
300 inline ~QWriteLocker()
301 { unlock(); }
302
303 inline void unlock()
304 {
305 if (q_val) {
306 if ((q_val & quintptr(1u)) == quintptr(1u)) {
307 q_val &= ~quintptr(1u);
308 readWriteLock()->unlock();
309 }
310 }
311 }
312
313 inline void relock()
314 {
315 if (q_val) {
316 if ((q_val & quintptr(1u)) == quintptr(0u)) {
317 readWriteLock()->lockForWrite();
318 q_val |= quintptr(1u);
319 }
320 }
321 }
322
323 inline QReadWriteLock *readWriteLock() const
324 { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
325
326
327private:
328 Q_DISABLE_COPY(QWriteLocker)
329 quintptr q_val;
330};
331
332inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock)
333 : q_val(reinterpret_cast<quintptr>(areadWriteLock))
334{
335 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
336 "QWriteLocker", "QReadWriteLock pointer is misaligned");
337 relock();
338}
339
340#if defined(Q_CC_MSVC)
341#pragma warning( pop )
342#endif
343
344#else // QT_CONFIG(thread)
345
346class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock
347{
348public:
349 enum RecursionMode { NonRecursive, Recursive };
350 inline explicit QReadWriteLock(RecursionMode = NonRecursive) noexcept { }
351 inline ~QReadWriteLock() { }
352
353 void lockForRead() noexcept { }
354 bool tryLockForRead() noexcept { return true; }
355 bool tryLockForRead(QDeadlineTimer) noexcept { return true; }
356 bool tryLockForRead(int timeout) noexcept { Q_UNUSED(timeout); return true; }
357
358 void lockForWrite() noexcept { }
359 bool tryLockForWrite() noexcept { return true; }
360 bool tryLockForWrite(QDeadlineTimer) noexcept { return true; }
361 bool tryLockForWrite(int timeout) noexcept { Q_UNUSED(timeout); return true; }
362
363 void unlock() noexcept { }
364
365private:
366 Q_DISABLE_COPY(QReadWriteLock)
367};
368
369class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
370{
371public:
372 Q_NODISCARD_CTOR
373 inline explicit QReadLocker(QReadWriteLock *) noexcept { }
374 inline ~QReadLocker() noexcept { }
375
376 void unlock() noexcept { }
377 void relock() noexcept { }
378 QReadWriteLock *readWriteLock() noexcept { return nullptr; }
379
380private:
381 Q_DISABLE_COPY(QReadLocker)
382};
383
384class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
385{
386public:
387 Q_NODISCARD_CTOR
388 inline explicit QWriteLocker(QReadWriteLock *) noexcept { }
389 inline ~QWriteLocker() noexcept { }
390
391 void unlock() noexcept { }
392 void relock() noexcept { }
393 QReadWriteLock *readWriteLock() noexcept { return nullptr; }
394
395private:
396 Q_DISABLE_COPY(QWriteLocker)
397};
398
399#endif // QT_CONFIG(thread)
400
401QT_END_NAMESPACE
402
403#endif // QREADWRITELOCK_H
Combined button and popup list for selecting options.
static QString appendSlashIfNeeded(const QString &path)