File indexing completed on 2026-09-15 09:20:07
0001
0002
0003
0004
0005 #ifndef QREADWRITELOCK_H
0006 #define QREADWRITELOCK_H
0007
0008 #include <QtCore/qglobal.h>
0009 #include <QtCore/qdeadlinetimer.h>
0010 #include <QtCore/qtsan_impl.h>
0011
0012 QT_BEGIN_NAMESPACE
0013
0014 #if QT_CONFIG(thread)
0015
0016 class QReadWriteLockPrivate;
0017
0018 class QBasicReadWriteLock
0019 {
0020 public:
0021 constexpr QBasicReadWriteLock() = default;
0022
0023 void lockForRead()
0024 {
0025 tryLockForReadInternal(QDeadlineTimer::Forever, 0);
0026 }
0027 bool tryLockForRead()
0028 {
0029 return tryLockForReadInternal(QDeadlineTimer(), QtTsan::TryLock);
0030 }
0031 bool tryLockForRead(QDeadlineTimer timeout)
0032 {
0033 return tryLockForReadInternal(timeout, QtTsan::TryLock);
0034 }
0035
0036 void lockForWrite()
0037 {
0038 tryLockForWriteInternal(QDeadlineTimer::Forever, 0);
0039 }
0040 bool tryLockForWrite()
0041 {
0042 return tryLockForWriteInternal(QDeadlineTimer(), QtTsan::TryLock);
0043 }
0044 bool tryLockForWrite(QDeadlineTimer timeout)
0045 {
0046 return tryLockForWriteInternal(timeout, QtTsan::TryLock);
0047 }
0048
0049 void unlock()
0050 {
0051 unsigned flags = 0;
0052 QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
0053 quintptr u = quintptr(d);
0054 Q_ASSERT_X(u, "QReadWriteLock::unlock()", "Cannot unlock an unlocked lock");
0055 if (u & StateLockedForRead)
0056 flags |= QtTsan::ReadLock;
0057 #ifdef QT_BUILDING_UNDER_TSAN
0058 else if (u > StateMask && isContendedLockForRead(d))
0059 flags |= QtTsan::ReadLock;
0060 #endif
0061
0062 QtTsan::mutexPreUnlock(this, flags);
0063 if (u > StateMask || !d_ptr.testAndSetRelease(d, nullptr, d))
0064 contendedUnlock(d);
0065 QtTsan::mutexPostUnlock(this, flags);
0066 }
0067
0068
0069 void lock() { lockForWrite(); }
0070 void lock_shared() { lockForRead(); }
0071 bool try_lock() { return tryLockForWrite(); }
0072 bool try_lock_shared() { return tryLockForRead(); }
0073 void unlock_shared() { unlock(); }
0074
0075 protected:
0076 static constexpr quintptr StateLockedForRead = 0x1;
0077 static constexpr quintptr StateLockedForWrite = 0x2;
0078 static constexpr quintptr StateMask = StateLockedForRead | StateLockedForWrite;
0079 static constexpr quintptr Counter = 0x10;
0080
0081 Q_ALWAYS_INLINE bool fastTryLockForRead(QReadWriteLockPrivate *&d)
0082 {
0083 if (d == nullptr) {
0084 auto dummyValue = reinterpret_cast<QReadWriteLockPrivate *>(StateLockedForRead);
0085 return d_ptr.testAndSetAcquire(nullptr, dummyValue, d);
0086 } else if (quintptr u = quintptr(d), v = u + Counter; u & StateLockedForRead) {
0087 return d_ptr.testAndSetAcquire(d, reinterpret_cast<QReadWriteLockPrivate *>(v), d);
0088 }
0089 return false;
0090 }
0091
0092 Q_ALWAYS_INLINE bool tryLockForReadInternal(QDeadlineTimer timeout, unsigned tsanFlags)
0093 {
0094 tsanFlags |= QtTsan::ReadLock;
0095 QtTsan::mutexPreLock(this, tsanFlags);
0096
0097 QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
0098 bool locked = fastTryLockForRead(d);
0099 if (!locked)
0100 locked = contendedTryLockForRead(timeout, d);
0101
0102 if (!locked)
0103 tsanFlags |= QtTsan::TryLockFailed;
0104 QtTsan::mutexPostLock(this, tsanFlags, 0);
0105 return locked;
0106 }
0107
0108 Q_ALWAYS_INLINE bool fastTryLockForWrite(QReadWriteLockPrivate *&d)
0109 {
0110 auto dummyValue = reinterpret_cast<QReadWriteLockPrivate *>(StateLockedForWrite);
0111 if (d == nullptr)
0112 return d_ptr.testAndSetAcquire(nullptr, dummyValue, d);
0113 return false;
0114 }
0115
0116 Q_ALWAYS_INLINE bool tryLockForWriteInternal(QDeadlineTimer timeout, unsigned tsanFlags)
0117 {
0118 QtTsan::mutexPreLock(this, tsanFlags);
0119
0120 QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
0121 bool locked = fastTryLockForWrite(d);
0122 if (!locked)
0123 locked = contendedTryLockForWrite(timeout, d);
0124
0125 if (!locked)
0126 tsanFlags |= QtTsan::TryLockFailed;
0127 QtTsan::mutexPostLock(this, tsanFlags, 0);
0128 return locked;
0129 }
0130
0131 Q_CORE_EXPORT bool contendedTryLockForRead(QDeadlineTimer timeout, void *dd);
0132 Q_CORE_EXPORT bool contendedTryLockForWrite(QDeadlineTimer timeout, void *dd);
0133 Q_CORE_EXPORT void contendedUnlock(void *dd);
0134 Q_CORE_EXPORT bool isContendedLockForRead(const void *dd) Q_DECL_PURE_FUNCTION;
0135
0136 constexpr QBasicReadWriteLock(QReadWriteLockPrivate *d) noexcept : d_ptr(d)
0137 {}
0138 Q_DISABLE_COPY(QBasicReadWriteLock)
0139 QAtomicPointer<QReadWriteLockPrivate> d_ptr = { nullptr };
0140 friend class QReadWriteLockPrivate;
0141 };
0142
0143 class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock : public QBasicReadWriteLock
0144 {
0145 public:
0146 enum RecursionMode { NonRecursive, Recursive };
0147
0148 QT_CORE_INLINE_SINCE(6, 6)
0149 explicit QReadWriteLock(RecursionMode recursionMode = NonRecursive);
0150 QT_CORE_INLINE_SINCE(6, 6)
0151 ~QReadWriteLock();
0152
0153 #if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
0154
0155 void lockForRead();
0156 bool tryLockForRead();
0157 #endif
0158 QT_CORE_INLINE_SINCE(6, 6)
0159 bool tryLockForRead(int timeout);
0160 #if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
0161 bool tryLockForRead(QDeadlineTimer timeout = {});
0162 #endif
0163 using QBasicReadWriteLock::tryLockForRead;
0164
0165 #if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
0166
0167 void lockForWrite();
0168 bool tryLockForWrite();
0169 #endif
0170 QT_CORE_INLINE_SINCE(6, 6)
0171 bool tryLockForWrite(int timeout);
0172 #if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
0173 bool tryLockForWrite(QDeadlineTimer timeout = {});
0174 #endif
0175 using QBasicReadWriteLock::tryLockForWrite;
0176
0177 #if QT_CORE_REMOVED_SINCE(6, 11) || defined(Q_QDOC)
0178 void unlock();
0179 #endif
0180
0181 private:
0182 QT7_ONLY(Q_CORE_EXPORT)
0183 static QReadWriteLockPrivate *initRecursive();
0184 QT7_ONLY(Q_CORE_EXPORT)
0185 static void destroyRecursive(QReadWriteLockPrivate *);
0186 };
0187
0188 #if QT_CORE_INLINE_IMPL_SINCE(6, 6)
0189 QReadWriteLock::QReadWriteLock(RecursionMode recursionMode)
0190 : QBasicReadWriteLock(recursionMode == Recursive ? initRecursive() : nullptr)
0191 {
0192 }
0193
0194 QReadWriteLock::~QReadWriteLock()
0195 {
0196 if (auto d = d_ptr.loadAcquire())
0197 destroyRecursive(d);
0198 }
0199
0200 bool QReadWriteLock::tryLockForRead(int timeout)
0201 {
0202 return tryLockForRead(QDeadlineTimer(timeout));
0203 }
0204
0205 bool QReadWriteLock::tryLockForWrite(int timeout)
0206 {
0207 return tryLockForWrite(QDeadlineTimer(timeout));
0208 }
0209 #endif
0210
0211 #if defined(Q_CC_MSVC)
0212 #pragma warning( push )
0213 #pragma warning( disable : 4312 )
0214 #endif
0215
0216 class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
0217 {
0218 public:
0219 Q_NODISCARD_CTOR
0220 inline QReadLocker(QReadWriteLock *readWriteLock);
0221
0222 inline ~QReadLocker()
0223 { unlock(); }
0224
0225 inline void unlock()
0226 {
0227 if (q_val) {
0228 if ((q_val & quintptr(1u)) == quintptr(1u)) {
0229 q_val &= ~quintptr(1u);
0230 readWriteLock()->unlock();
0231 }
0232 }
0233 }
0234
0235 inline void relock()
0236 {
0237 if (q_val) {
0238 if ((q_val & quintptr(1u)) == quintptr(0u)) {
0239 readWriteLock()->lockForRead();
0240 q_val |= quintptr(1u);
0241 }
0242 }
0243 }
0244
0245 inline QReadWriteLock *readWriteLock() const
0246 { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
0247
0248 private:
0249 Q_DISABLE_COPY(QReadLocker)
0250 quintptr q_val;
0251 };
0252
0253 inline QReadLocker::QReadLocker(QReadWriteLock *areadWriteLock)
0254 : q_val(reinterpret_cast<quintptr>(areadWriteLock))
0255 {
0256 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
0257 "QReadLocker", "QReadWriteLock pointer is misaligned");
0258 relock();
0259 }
0260
0261 class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
0262 {
0263 public:
0264 Q_NODISCARD_CTOR
0265 inline QWriteLocker(QReadWriteLock *readWriteLock);
0266
0267 inline ~QWriteLocker()
0268 { unlock(); }
0269
0270 inline void unlock()
0271 {
0272 if (q_val) {
0273 if ((q_val & quintptr(1u)) == quintptr(1u)) {
0274 q_val &= ~quintptr(1u);
0275 readWriteLock()->unlock();
0276 }
0277 }
0278 }
0279
0280 inline void relock()
0281 {
0282 if (q_val) {
0283 if ((q_val & quintptr(1u)) == quintptr(0u)) {
0284 readWriteLock()->lockForWrite();
0285 q_val |= quintptr(1u);
0286 }
0287 }
0288 }
0289
0290 inline QReadWriteLock *readWriteLock() const
0291 { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
0292
0293
0294 private:
0295 Q_DISABLE_COPY(QWriteLocker)
0296 quintptr q_val;
0297 };
0298
0299 inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock)
0300 : q_val(reinterpret_cast<quintptr>(areadWriteLock))
0301 {
0302 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
0303 "QWriteLocker", "QReadWriteLock pointer is misaligned");
0304 relock();
0305 }
0306
0307 #if defined(Q_CC_MSVC)
0308 #pragma warning( pop )
0309 #endif
0310
0311 #else
0312
0313 class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock
0314 {
0315 public:
0316 enum RecursionMode { NonRecursive, Recursive };
0317 inline explicit QReadWriteLock(RecursionMode = NonRecursive) noexcept { }
0318 inline ~QReadWriteLock() { }
0319
0320 void lockForRead() noexcept { }
0321 bool tryLockForRead() noexcept { return true; }
0322 bool tryLockForRead(QDeadlineTimer) noexcept { return true; }
0323 bool tryLockForRead(int timeout) noexcept { Q_UNUSED(timeout); return true; }
0324
0325 void lockForWrite() noexcept { }
0326 bool tryLockForWrite() noexcept { return true; }
0327 bool tryLockForWrite(QDeadlineTimer) noexcept { return true; }
0328 bool tryLockForWrite(int timeout) noexcept { Q_UNUSED(timeout); return true; }
0329
0330 void unlock() noexcept { }
0331
0332 private:
0333 Q_DISABLE_COPY(QReadWriteLock)
0334 };
0335
0336 class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
0337 {
0338 public:
0339 Q_NODISCARD_CTOR
0340 inline explicit QReadLocker(QReadWriteLock *) noexcept { }
0341 inline ~QReadLocker() noexcept { }
0342
0343 void unlock() noexcept { }
0344 void relock() noexcept { }
0345 QReadWriteLock *readWriteLock() noexcept { return nullptr; }
0346
0347 private:
0348 Q_DISABLE_COPY(QReadLocker)
0349 };
0350
0351 class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
0352 {
0353 public:
0354 Q_NODISCARD_CTOR
0355 inline explicit QWriteLocker(QReadWriteLock *) noexcept { }
0356 inline ~QWriteLocker() noexcept { }
0357
0358 void unlock() noexcept { }
0359 void relock() noexcept { }
0360 QReadWriteLock *readWriteLock() noexcept { return nullptr; }
0361
0362 private:
0363 Q_DISABLE_COPY(QWriteLocker)
0364 };
0365
0366 #endif
0367
0368 QT_END_NAMESPACE
0369
0370 #endif