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(
const QReadWriteLockPrivate *d, uint flags = 0)
noexcept
135#ifdef QT_BUILDING_UNDER_TSAN
136 u = describeLockInternal(d);
140 if (u & StateLockedForRead)
141 flags |= QtTsan::ReadLock;
145 constexpr QBasicReadWriteLock(QReadWriteLockPrivate *d)
noexcept : d_ptr(d)
147 Q_DISABLE_COPY(QBasicReadWriteLock)
148 QAtomicPointer<QReadWriteLockPrivate> d_ptr = {
nullptr };
149 friend class QReadWriteLockPrivate;
152class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock :
public QBasicReadWriteLock
155 enum RecursionMode { NonRecursive, Recursive };
157 QT_CORE_INLINE_SINCE(6, 6)
158 explicit QReadWriteLock(RecursionMode recursionMode = NonRecursive);
159 QT_CORE_INLINE_SINCE(6, 6)
162#if QT_CORE_REMOVED_SINCE(6
, 11
) || defined(Q_QDOC)
165 bool tryLockForRead();
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 = {});
172 using QBasicReadWriteLock::tryLockForRead;
174#if QT_CORE_REMOVED_SINCE(6
, 11
) || defined(Q_QDOC)
177 bool tryLockForWrite();
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 = {});
184 using QBasicReadWriteLock::tryLockForWrite;
186#if QT_CORE_REMOVED_SINCE(6
, 11
) || defined(Q_QDOC)
191#if QT_CORE_REMOVED_SINCE(6
, 12
)
192 static QReadWriteLockPrivate *initRecursive();
193 static void destroyRecursive(QReadWriteLockPrivate *);
196 QT7_ONLY(Q_CORE_EXPORT)
static void *initRecursiveHelper();
197 QT7_ONLY(Q_CORE_EXPORT)
static void destroyRecursiveHelper(
void *)
noexcept;
198 static QReadWriteLockPrivate *initRecursive2()
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;
207 __tsan_mutex_create(d, flags);
211 static void destroyRecursive2(QReadWriteLockPrivate *d)
213#ifdef QT_BUILDING_UNDER_TSAN
215 __tsan_mutex_destroy(d, flags);
217 destroyRecursiveHelper(d);
221#if QT_CORE_INLINE_IMPL_SINCE(6
, 6
)
222QReadWriteLock::QReadWriteLock(RecursionMode recursionMode)
223 : QBasicReadWriteLock(recursionMode == Recursive ? initRecursive2() :
nullptr)
227QReadWriteLock::~QReadWriteLock()
229 if (
auto d = d_ptr.loadAcquire())
230 destroyRecursive2(d);
233bool QReadWriteLock::tryLockForRead(
int timeout)
235 return tryLockForRead(QDeadlineTimer(timeout));
238bool QReadWriteLock::tryLockForWrite(
int timeout)
240 return tryLockForWrite(QDeadlineTimer(timeout));
244#if defined(Q_CC_MSVC)
245#pragma warning( push )
246#pragma warning( disable : 4312
)
249class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
253 inline QReadLocker(QReadWriteLock *readWriteLock);
255 inline ~QReadLocker()
261 if ((q_val & quintptr(1u)) == quintptr(1u)) {
262 q_val &= ~quintptr(1u);
263 readWriteLock()->unlock();
271 if ((q_val & quintptr(1u)) == quintptr(0u)) {
272 readWriteLock()->lockForRead();
273 q_val |= quintptr(1u);
278 inline QReadWriteLock *readWriteLock()
const
279 {
return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
282 Q_DISABLE_COPY(QReadLocker)
286inline QReadLocker::QReadLocker(QReadWriteLock *areadWriteLock)
287 : q_val(
reinterpret_cast<quintptr>(areadWriteLock))
289 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
290 "QReadLocker",
"QReadWriteLock pointer is misaligned");
294class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
298 inline QWriteLocker(QReadWriteLock *readWriteLock);
300 inline ~QWriteLocker()
306 if ((q_val & quintptr(1u)) == quintptr(1u)) {
307 q_val &= ~quintptr(1u);
308 readWriteLock()->unlock();
316 if ((q_val & quintptr(1u)) == quintptr(0u)) {
317 readWriteLock()->lockForWrite();
318 q_val |= quintptr(1u);
323 inline QReadWriteLock *readWriteLock()
const
324 {
return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); }
328 Q_DISABLE_COPY(QWriteLocker)
332inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock)
333 : q_val(
reinterpret_cast<quintptr>(areadWriteLock))
335 Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0),
336 "QWriteLocker",
"QReadWriteLock pointer is misaligned");
340#if defined(Q_CC_MSVC)
341#pragma warning( pop )
346class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock
349 enum RecursionMode { NonRecursive, Recursive };
350 inline explicit QReadWriteLock(RecursionMode = NonRecursive)
noexcept { }
351 inline ~QReadWriteLock() { }
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; }
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; }
363 void unlock()
noexcept { }
366 Q_DISABLE_COPY(QReadWriteLock)