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(QReadWriteLockPrivate *d, uint flags = 0) noexcept
133 {
134 if constexpr (QtTsan::IsEnabled) {
135 if (describeLockInternal(d) & StateLockedForRead)
136 flags |= QtTsan::ReadLock;
137 }
138 return flags;
139 }
140
141 constexpr QBasicReadWriteLock(QReadWriteLockPrivate *d) noexcept : d_ptr(d)
142 {}
143 Q_DISABLE_COPY(QBasicReadWriteLock)
144 QAtomicPointer<QReadWriteLockPrivate> d_ptr = { nullptr };
145 friend class QReadWriteLockPrivate;
146};
147
148class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock : public QBasicReadWriteLock
149{
150public:
151 enum RecursionMode { NonRecursive, Recursive };
152
153 QT_CORE_INLINE_SINCE(6, 6)
154 explicit QReadWriteLock(RecursionMode recursionMode = NonRecursive);
155 QT_CORE_INLINE_SINCE(6, 6)
156 ~QReadWriteLock();
157
158#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
159 // was: QT_CORE_INLINE_SINCE(6, 6)
160 void lockForRead();
161 bool tryLockForRead();
162#endif
163 QT_CORE_INLINE_SINCE(6, 6)
164 bool tryLockForRead(int timeout);
165#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
166 bool tryLockForRead(QDeadlineTimer timeout = {});
167#endif
168 using QBasicReadWriteLock::tryLockForRead;
169
170#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
171 // was: QT_CORE_INLINE_SINCE(6, 6)
172 void lockForWrite();
173 bool tryLockForWrite();
174#endif
175 QT_CORE_INLINE_SINCE(6, 6)
176 bool tryLockForWrite(int timeout);
177#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
178 bool tryLockForWrite(QDeadlineTimer timeout = {});
179#endif
180 using QBasicReadWriteLock::tryLockForWrite;
181
182#if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
183 void unlock();
184#endif
185
186private:
187#if QT_CORE_REMOVED_SINCE(6, 12)
188 static QReadWriteLockPrivate *initRecursive();
189 static void destroyRecursive(QReadWriteLockPrivate *);
190#endif
191
192 QT7_ONLY(Q_CORE_EXPORT) static void *initRecursiveHelper();
193 QT7_ONLY(Q_CORE_EXPORT) static void destroyRecursiveHelper(void *) noexcept;
194 static QReadWriteLockPrivate *initRecursive2()
195 {
196 auto d = static_cast<QReadWriteLockPrivate *>(initRecursiveHelper());
197 Q_PRESUME(quintptr(d) > StateMask);
198#ifdef QT_BUILDING_UNDER_TSAN
199 unsigned flags = __tsan_mutex_write_reentrant | __tsan_mutex_read_reentrant;
200# if (defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1200) || (defined(Q_CC_CLANG) && Q_CC_CLANG >= 1200)
201 flags |= __tsan_mutex_not_static;
202# endif
203 __tsan_mutex_create(d, flags);
204#endif
205 return d;
206 }
207 static void destroyRecursive2(QReadWriteLockPrivate *d)
208 {
209#ifdef QT_BUILDING_UNDER_TSAN
210 unsigned flags = 0;
211 __tsan_mutex_destroy(d, flags);
212#endif
213 destroyRecursiveHelper(d);
214 }
215};
216
217#if QT_CORE_INLINE_IMPL_SINCE(6, 6)
218QReadWriteLock::QReadWriteLock(RecursionMode recursionMode)
219 : QBasicReadWriteLock(recursionMode == Recursive ? initRecursive2() : nullptr)
220{
221}
222
223QReadWriteLock::~QReadWriteLock()
224{
225 if (auto d = d_ptr.loadAcquire())
226 destroyRecursive2(d);
227}
228
229bool QReadWriteLock::tryLockForRead(int timeout)
230{
231 return tryLockForRead(QDeadlineTimer(timeout));
232}
233
234bool QReadWriteLock::tryLockForWrite(int timeout)
235{
236 return tryLockForWrite(QDeadlineTimer(timeout));
237}
238#endif // inline since 6.6
239
240#if defined(Q_CC_MSVC)
241#pragma warning( push )
242#pragma warning( disable : 4312 ) // ignoring the warning from /Wp64
243#endif
244
245class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
246{
247public:
248 Q_NODISCARD_CTOR
249 inline QReadLocker(QReadWriteLock *readWriteLock);
250
251 inline ~QReadLocker()
252 { unlock(); }
253
254 inline void unlock()
255 {
256 if (q_val) {
257 if ((q_val & quintptr(1u)) == quintptr(1u)) {
258 q_val &= ~quintptr(1u);
259 readWriteLock()->unlock();
260 }
261 }
262 }
263
264 inline void relock()
265 {
266 if (q_val) {
267 if ((q_val & quintptr(1u)) == quintptr(0u)) {
268 readWriteLock()->lockForRead();
269 q_val |= quintptr(1u);
270 }
271 }
272 }
273
274 inline QReadWriteLock *readWriteLock() const
275 { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
276
277private:
278 Q_DISABLE_COPY(QReadLocker)
279 quintptr q_val;
280};
281
282inline QReadLocker::QReadLocker(QReadWriteLock *areadWriteLock)
283 : q_val(reinterpret_cast<quintptr>(areadWriteLock))
284{
285 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
286 "QReadLocker", "QReadWriteLock pointer is misaligned");
287 relock();
288}
289
290class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
291{
292public:
293 Q_NODISCARD_CTOR
294 inline QWriteLocker(QReadWriteLock *readWriteLock);
295
296 inline ~QWriteLocker()
297 { unlock(); }
298
299 inline void unlock()
300 {
301 if (q_val) {
302 if ((q_val & quintptr(1u)) == quintptr(1u)) {
303 q_val &= ~quintptr(1u);
304 readWriteLock()->unlock();
305 }
306 }
307 }
308
309 inline void relock()
310 {
311 if (q_val) {
312 if ((q_val & quintptr(1u)) == quintptr(0u)) {
313 readWriteLock()->lockForWrite();
314 q_val |= quintptr(1u);
315 }
316 }
317 }
318
319 inline QReadWriteLock *readWriteLock() const
320 { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
321
322
323private:
324 Q_DISABLE_COPY(QWriteLocker)
325 quintptr q_val;
326};
327
328inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock)
329 : q_val(reinterpret_cast<quintptr>(areadWriteLock))
330{
331 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
332 "QWriteLocker", "QReadWriteLock pointer is misaligned");
333 relock();
334}
335
336#if defined(Q_CC_MSVC)
337#pragma warning( pop )
338#endif
339
340#else // QT_CONFIG(thread)
341
342class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock
343{
344public:
345 enum RecursionMode { NonRecursive, Recursive };
346 inline explicit QReadWriteLock(RecursionMode = NonRecursive) noexcept { }
347 inline ~QReadWriteLock() { }
348
349 void lockForRead() noexcept { }
350 bool tryLockForRead() noexcept { return true; }
351 bool tryLockForRead(QDeadlineTimer) noexcept { return true; }
352 bool tryLockForRead(int timeout) noexcept { Q_UNUSED(timeout); return true; }
353
354 void lockForWrite() noexcept { }
355 bool tryLockForWrite() noexcept { return true; }
356 bool tryLockForWrite(QDeadlineTimer) noexcept { return true; }
357 bool tryLockForWrite(int timeout) noexcept { Q_UNUSED(timeout); return true; }
358
359 void unlock() noexcept { }
360
361private:
362 Q_DISABLE_COPY(QReadWriteLock)
363};
364
365class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
366{
367public:
368 Q_NODISCARD_CTOR
369 inline explicit QReadLocker(QReadWriteLock *) noexcept { }
370 inline ~QReadLocker() noexcept { }
371
372 void unlock() noexcept { }
373 void relock() noexcept { }
374 QReadWriteLock *readWriteLock() noexcept { return nullptr; }
375
376private:
377 Q_DISABLE_COPY(QReadLocker)
378};
379
380class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
381{
382public:
383 Q_NODISCARD_CTOR
384 inline explicit QWriteLocker(QReadWriteLock *) noexcept { }
385 inline ~QWriteLocker() noexcept { }
386
387 void unlock() noexcept { }
388 void relock() noexcept { }
389 QReadWriteLock *readWriteLock() noexcept { return nullptr; }
390
391private:
392 Q_DISABLE_COPY(QWriteLocker)
393};
394
395#endif // QT_CONFIG(thread)
396
397QT_END_NAMESPACE
398
399#endif // QREADWRITELOCK_H
Combined button and popup list for selecting options.
static QString appendSlashIfNeeded(const QString &path)