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