7#include "qplatformdefs.h"
12#include "private/qfreelist_p.h"
13#include "private/qlocking_p.h"
20
21
22
23
24
25
26
27
28
29
33 return reinterpret_cast<QReadWriteLockPrivate *>(QReadWriteLockPrivate::StateLockedForRead);
37 return reinterpret_cast<QReadWriteLockPrivate *>(QReadWriteLockPrivate::StateLockedForWrite);
42 return quintptr(d) & QReadWriteLockPrivate::StateMask;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
89
90
91
92
93
94
95
96
97
98
99
100
103
104
105
106
107
108
109
110
111
112void *QReadWriteLock::initRecursiveHelper()
114 auto d =
new QReadWriteLockPrivate(
true);
115 Q_ASSERT_X(!(quintptr(d) & StateMask),
"QReadWriteLock::QReadWriteLock",
"bad d_ptr alignment");
120
121
122
123
124
125
126void QReadWriteLock::destroyRecursiveHelper(
void *dd)
noexcept
128 auto d =
static_cast<QReadWriteLockPrivate *>(dd);
129 if (isUncontendedLocked(d)) {
130 qWarning(
"QReadWriteLock: destroying locked QReadWriteLock");
137
138
139
140
141
142
143
144
145
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
169 QReadWriteLockPrivate *dummyValue,
170 QReadWriteLockPrivate *&d)
173 return d ==
nullptr && d_ptr.testAndSetAcquire(
nullptr, dummyValue, d);
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
196QBasicReadWriteLock::contendedTryLockForRead(QDeadlineTimer timeout,
void *dd)
198 auto d =
static_cast<QReadWriteLockPrivate *>(dd);
202 if (fastTryLock(d_ptr, dummyLockedForRead(), d))
207 if ((quintptr(d) & StateMask) == StateLockedForRead) {
209 const auto val =
reinterpret_cast<QReadWriteLockPrivate *>(quintptr(d) + Counter);
210 Q_ASSERT_X(quintptr(val) > Counter,
"QReadWriteLock::tryLockForRead()",
211 "Overflow in lock counter");
212 if (!d_ptr.testAndSetAcquire(d, val, d))
217 if (d == dummyLockedForWrite()) {
218 if (timeout.hasExpired())
222 auto val = QReadWriteLockPrivate::allocate();
223 val->writerCount = 1;
224 if (!d_ptr.testAndSetOrdered(d, val, d)) {
225 val->writerCount = 0;
231 Q_ASSERT(!isUncontendedLocked(d));
233 d = d_ptr.loadAcquire();
234 if (!d || isUncontendedLocked(d))
238 return d->recursiveLockForRead(timeout);
240 auto lock = qt_unique_lock(d->mutex);
241 if (QReadWriteLockPrivate *dd = d_ptr.loadAcquire(); d != dd) {
251 return d->lockForRead(lock, timeout);
256
257
258
259
260
261
262
263
264
265
266
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
309QBasicReadWriteLock::contendedTryLockForWrite(QDeadlineTimer timeout,
void *dd)
311 auto d =
static_cast<QReadWriteLockPrivate *>(dd);
315 if (fastTryLock(d_ptr, dummyLockedForWrite(), d))
320 if (isUncontendedLocked(d)) {
321 if (timeout.hasExpired())
325 auto val = QReadWriteLockPrivate::allocate();
326 if (d == dummyLockedForWrite())
327 val->writerCount = 1;
329 val->readerCount = (quintptr(d) >> 4) + 1;
330 if (!d_ptr.testAndSetOrdered(d, val, d)) {
331 val->writerCount = val->readerCount = 0;
337 Q_ASSERT(!isUncontendedLocked(d));
339 d = d_ptr.loadAcquire();
340 if (!d || isUncontendedLocked(d))
344 return d->recursiveLockForWrite(timeout);
346 auto lock = qt_unique_lock(d->mutex);
347 if (QReadWriteLockPrivate *dd = d_ptr.loadAcquire(); d != dd) {
354 return d->lockForWrite(lock, timeout);
359
360
361
362
363
364
365
366
367
368quintptr QBasicReadWriteLock::describeLockInternal(
void *dd)
noexcept
370 return QReadWriteLockPrivate::describeState(dd);
374
375
376
377
378
379
380
381
383void QBasicReadWriteLock::contendedUnlock(
void *dd)
385 auto d =
static_cast<QReadWriteLockPrivate *>(dd);
387 Q_ASSERT_X(d,
"QReadWriteLock::unlock()",
"Cannot unlock an unlocked lock");
390 if (quintptr(d) <= 2) {
391 if (!d_ptr.testAndSetOrdered(d,
nullptr, d))
396 if ((quintptr(d) & StateMask) == StateLockedForRead) {
397 Q_ASSERT(quintptr(d) > Counter);
399 auto val =
reinterpret_cast<QReadWriteLockPrivate *>(quintptr(d) - (1U<<4));
400 if (!d_ptr.testAndSetOrdered(d, val, d))
405 Q_ASSERT(!isUncontendedLocked(d));
408 d->recursiveUnlock();
412 const auto lock = qt_scoped_lock(d->mutex);
413 if (d->writerCount) {
414 Q_ASSERT(d->writerCount == 1);
415 Q_ASSERT(d->readerCount == 0);
418 Q_ASSERT(d->readerCount > 0);
420 if (d->readerCount > 0)
424 if (d->waitingReaders || d->waitingWriters) {
427 Q_ASSERT(d_ptr.loadRelaxed() == d);
428 d_ptr.storeRelease(
nullptr);
435bool QReadWriteLockPrivate::lockForRead(
std::unique_lock<
std::mutex> &lock, QDeadlineTimer timeout)
437 using std::chrono::steady_clock;
438 Q_ASSERT(!mutex.try_lock());
440 while (waitingWriters || writerCount) {
441 if (timeout.hasExpired())
443 if (!timeout.isForever()) {
445 readerCond.wait_until(lock, timeout.deadline<steady_clock>());
448 readerCond.wait(lock);
453 Q_ASSERT(writerCount == 0);
457bool QReadWriteLockPrivate::lockForWrite(
std::unique_lock<
std::mutex> &lock, QDeadlineTimer timeout)
459 using std::chrono::steady_clock;
460 Q_ASSERT(!mutex.try_lock());
462 while (readerCount || writerCount) {
463 if (timeout.hasExpired()) {
464 if (waitingReaders && !waitingWriters && !writerCount) {
467 readerCond.notify_all();
471 if (!timeout.isForever()) {
473 writerCond.wait_until(lock, timeout.deadline<steady_clock>());
476 writerCond.wait(lock);
481 Q_ASSERT(writerCount == 0);
482 Q_ASSERT(readerCount == 0);
487void QReadWriteLockPrivate::unlock()
489 Q_ASSERT(!mutex.try_lock());
491 writerCond.notify_one();
492 else if (waitingReaders)
493 readerCond.notify_all();
498 return [handle](QReadWriteLockPrivate::Reader reader) {
return reader.handle == handle; };
501bool QReadWriteLockPrivate::recursiveLockForRead(QDeadlineTimer timeout)
504 auto lock = qt_unique_lock(mutex);
506 Qt::HANDLE self = QThread::currentThreadId();
508 auto it =
std::find_if(currentReaders.begin(), currentReaders.end(),
510 if (it != currentReaders.end()) {
511 ++it->recursionLevel;
515 if (!lockForRead(lock, timeout))
518 Reader r = {self, 1};
519 currentReaders.append(std::move(r));
523bool QReadWriteLockPrivate::recursiveLockForWrite(QDeadlineTimer timeout)
526 auto lock = qt_unique_lock(mutex);
528 Qt::HANDLE self = QThread::currentThreadId();
529 if (currentWriter == self) {
534 if (!lockForWrite(lock, timeout))
537 currentWriter = self;
541void QReadWriteLockPrivate::recursiveUnlock()
544 auto lock = qt_unique_lock(mutex);
546 Qt::HANDLE self = QThread::currentThreadId();
547 if (self == currentWriter) {
548 if (--writerCount > 0)
550 currentWriter =
nullptr;
552 auto it =
std::find_if(currentReaders.begin(), currentReaders.end(),
554 if (it == currentReaders.end()) {
555 qWarning(
"QReadWriteLock::unlock: unlocking from a thread that did not lock");
558 if (--it->recursionLevel <= 0) {
559 currentReaders.erase(it);
572struct QReadWriteLockFreeListConstants : QFreeListDefaultConstants
574 enum { BlockCount = 4, MaxIndex=0xffff };
575 static const int Sizes[BlockCount];
578 QReadWriteLockFreeListConstants::Sizes[QReadWriteLockFreeListConstants::BlockCount] = {
579 16, 128, 1024, QReadWriteLockFreeListConstants::MaxIndex - (16 + 128 + 1024)
582typedef QFreeList<QReadWriteLockPrivate, QReadWriteLockFreeListConstants> QReadWriteLockFreeList;
583Q_GLOBAL_STATIC(QReadWriteLockFreeList, qrwl_freelist);
586QReadWriteLockPrivate *QReadWriteLockPrivate::allocate()
588 int i = qrwl_freelist->next();
589 QReadWriteLockPrivate *d = &(*qrwl_freelist)[i];
591 Q_ASSERT(!d->recursive);
592 Q_ASSERT(!d->waitingReaders && !d->waitingWriters && !d->readerCount && !d->writerCount);
596void QReadWriteLockPrivate::release()
598 Q_ASSERT(!recursive);
599 Q_ASSERT(!waitingReaders && !waitingWriters && !readerCount && !writerCount);
600 qrwl_freelist->release(id);
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
637
638
639
640
641
642
643
644
647
648
649
650
651
652
653
656
657
658
659
660
661
664
665
666
667
668
669
672
673
674
675
676
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
712
713
714
715
716
717
718
719
722
723
724
725
726
727
728
731
732
733
734
735
736
739
740
741
742
743
744
747
748
749
750
751
static Q_ALWAYS_INLINE bool fastTryLock(QAtomicPointer< QReadWriteLockPrivate > &d_ptr, QReadWriteLockPrivate *dummyValue, QReadWriteLockPrivate *&d)
static QT_BEGIN_NAMESPACE auto dummyLockedForRead()
static bool isUncontendedLocked(const QReadWriteLockPrivate *d)
static auto dummyLockedForWrite()
static auto handleEquals(Qt::HANDLE handle)