16class QReadWriteLockPrivate;
18class QBasicReadWriteLock
21 constexpr QBasicReadWriteLock() =
default;
25 tryLockForReadInternal(QDeadlineTimer::Forever, 0);
29 return tryLockForReadInternal(QDeadlineTimer(), QtTsan::TryLock);
31 bool tryLockForRead(QDeadlineTimer timeout)
33 return tryLockForReadInternal(timeout, QtTsan::TryLock);
38 tryLockForWriteInternal(QDeadlineTimer::Forever, 0);
40 bool tryLockForWrite()
42 return tryLockForWriteInternal(QDeadlineTimer(), QtTsan::TryLock);
44 bool tryLockForWrite(QDeadlineTimer timeout)
46 return tryLockForWriteInternal(timeout, QtTsan::TryLock);
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");
56 QtTsan::mutexPreUnlock(
this, flags);
57 if (u > StateMask || !d_ptr.testAndSetRelease(d,
nullptr, d))
59 QtTsan::mutexPostUnlock(
this, flags);
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(); }
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;
75 Q_ALWAYS_INLINE
bool fastTryLockForRead(QReadWriteLockPrivate *&d)
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);
86 Q_ALWAYS_INLINE
bool tryLockForReadInternal(QDeadlineTimer timeout,
unsigned tsanFlags)
88 tsanFlags |= QtTsan::ReadLock;
89 QtTsan::mutexPreLock(
this, tsanFlags);
91 QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
92 bool locked = fastTryLockForRead(d);
94 locked = contendedTryLockForRead(timeout, d);
97 tsanFlags |= QtTsan::TryLockFailed;
98 QtTsan::mutexPostLock(
this, tsanFlags, 0);
102 Q_ALWAYS_INLINE
bool fastTryLockForWrite(QReadWriteLockPrivate *&d)
104 auto dummyValue =
reinterpret_cast<QReadWriteLockPrivate *>(StateLockedForWrite);
106 return d_ptr.testAndSetAcquire(
nullptr, dummyValue, d);
110 Q_ALWAYS_INLINE
bool tryLockForWriteInternal(QDeadlineTimer timeout,
unsigned tsanFlags)
112 QtTsan::mutexPreLock(
this, tsanFlags);
114 QReadWriteLockPrivate *d = d_ptr.loadRelaxed();
115 bool locked = fastTryLockForWrite(d);
117 locked = contendedTryLockForWrite(timeout, d);
120 tsanFlags |= QtTsan::TryLockFailed;
121 QtTsan::mutexPostLock(
this, tsanFlags, 0);
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;
131 static Q_CORE_EXPORT quintptr describeLockInternal(
void *dd)
noexcept Q_DECL_PURE_FUNCTION;
132 static uint describeLockForTSan(QReadWriteLockPrivate *d, uint flags = 0)
noexcept
134 if constexpr (QtTsan::IsEnabled) {
135 if (describeLockInternal(d) & StateLockedForRead)
136 flags |= QtTsan::ReadLock;
141 constexpr QBasicReadWriteLock(QReadWriteLockPrivate *d)
noexcept : d_ptr(d)
143 Q_DISABLE_COPY(QBasicReadWriteLock)
144 QAtomicPointer<QReadWriteLockPrivate> d_ptr = {
nullptr };
145 friend class QReadWriteLockPrivate;
148class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock :
public QBasicReadWriteLock
151 enum RecursionMode { NonRecursive, Recursive };
153 QT_CORE_INLINE_SINCE(6, 6)
154 explicit QReadWriteLock(RecursionMode recursionMode = NonRecursive);
155 QT_CORE_INLINE_SINCE(6, 6)
158#if QT_CORE_REMOVED_SINCE(6
, 11
) || defined(Q_QDOC)
161 bool tryLockForRead();
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 = {});
168 using QBasicReadWriteLock::tryLockForRead;
170#if QT_CORE_REMOVED_SINCE(6
, 11
) || defined(Q_QDOC)
173 bool tryLockForWrite();
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 = {});
180 using QBasicReadWriteLock::tryLockForWrite;
182#if QT_CORE_REMOVED_SINCE(6
, 11
) || defined(Q_QDOC)
187#if QT_CORE_REMOVED_SINCE(6
, 12
)
188 static QReadWriteLockPrivate *initRecursive();
189 static void destroyRecursive(QReadWriteLockPrivate *);
192 QT7_ONLY(Q_CORE_EXPORT)
static void *initRecursiveHelper();
193 QT7_ONLY(Q_CORE_EXPORT)
static void destroyRecursiveHelper(
void *)
noexcept;
194 static QReadWriteLockPrivate *initRecursive2()
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;
203 __tsan_mutex_create(d, flags);
207 static void destroyRecursive2(QReadWriteLockPrivate *d)
209#ifdef QT_BUILDING_UNDER_TSAN
211 __tsan_mutex_destroy(d, flags);
213 destroyRecursiveHelper(d);
217#if QT_CORE_INLINE_IMPL_SINCE(6
, 6
)
218QReadWriteLock::QReadWriteLock(RecursionMode recursionMode)
219 : QBasicReadWriteLock(recursionMode == Recursive ? initRecursive2() :
nullptr)
223QReadWriteLock::~QReadWriteLock()
225 if (
auto d = d_ptr.loadAcquire())
226 destroyRecursive2(d);
229bool QReadWriteLock::tryLockForRead(
int timeout)
231 return tryLockForRead(QDeadlineTimer(timeout));
234bool QReadWriteLock::tryLockForWrite(
int timeout)
236 return tryLockForWrite(QDeadlineTimer(timeout));
240#if defined(Q_CC_MSVC)
241#pragma warning( push )
242#pragma warning( disable : 4312
)
245class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
249 inline QReadLocker(QReadWriteLock *readWriteLock);
251 inline ~QReadLocker()
257 if ((q_val & quintptr(1u)) == quintptr(1u)) {
258 q_val &= ~quintptr(1u);
259 readWriteLock()->unlock();
267 if ((q_val & quintptr(1u)) == quintptr(0u)) {
268 readWriteLock()->lockForRead();
269 q_val |= quintptr(1u);
274 inline QReadWriteLock *readWriteLock()
const
275 {
return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
278 Q_DISABLE_COPY(QReadLocker)
282inline QReadLocker::QReadLocker(QReadWriteLock *areadWriteLock)
283 : q_val(
reinterpret_cast<quintptr>(areadWriteLock))
285 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
286 "QReadLocker",
"QReadWriteLock pointer is misaligned");
290class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
294 inline QWriteLocker(QReadWriteLock *readWriteLock);
296 inline ~QWriteLocker()
302 if ((q_val & quintptr(1u)) == quintptr(1u)) {
303 q_val &= ~quintptr(1u);
304 readWriteLock()->unlock();
312 if ((q_val & quintptr(1u)) == quintptr(0u)) {
313 readWriteLock()->lockForWrite();
314 q_val |= quintptr(1u);
319 inline QReadWriteLock *readWriteLock()
const
320 {
return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
324 Q_DISABLE_COPY(QWriteLocker)
328inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock)
329 : q_val(
reinterpret_cast<quintptr>(areadWriteLock))
331 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
332 "QWriteLocker",
"QReadWriteLock pointer is misaligned");
336#if defined(Q_CC_MSVC)
337#pragma warning( pop )
342class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock
345 enum RecursionMode { NonRecursive, Recursive };
346 inline explicit QReadWriteLock(RecursionMode = NonRecursive)
noexcept { }
347 inline ~QReadWriteLock() { }
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; }
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; }
359 void unlock()
noexcept { }
362 Q_DISABLE_COPY(QReadWriteLock)