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
31using namespace QReadWriteLockStates;
34using steady_clock =
std::chrono::steady_clock;
36const auto dummyLockedForRead =
reinterpret_cast<QReadWriteLockPrivate *>(quintptr(StateLockedForRead));
37const auto dummyLockedForWrite =
reinterpret_cast<QReadWriteLockPrivate *>(quintptr(StateLockedForWrite));
39{
return quintptr(d) & StateMask; }
43
44
45
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
86
87
88
89
90
91
92
93
94
95
96
97
100
101
102
103
104
105
106
107
108
109QReadWriteLockPrivate *QReadWriteLock::initRecursive()
111 auto d =
new QReadWriteLockPrivate(
true);
112 Q_ASSERT_X(!(quintptr(d) & StateMask),
"QReadWriteLock::QReadWriteLock",
"bad d_ptr alignment");
117
118
119
120
121
122
123void QReadWriteLock::destroyRecursive(QReadWriteLockPrivate *d)
125 if (isUncontendedLocked(d)) {
126 qWarning(
"QReadWriteLock: destroying locked QReadWriteLock");
133
134
135
136
137
138
139
140
141
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
169 return d ==
nullptr && d_ptr.testAndSetAcquire(
nullptr, dummyValue, d);
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
192QBasicReadWriteLock::contendedTryLockForRead(QDeadlineTimer timeout,
void *dd)
194 auto d =
static_cast<QReadWriteLockPrivate *>(dd);
198 if (fastTryLock(d_ptr, dummyLockedForRead, d))
203 if ((quintptr(d) & StateMask) == StateLockedForRead) {
205 const auto val =
reinterpret_cast<QReadWriteLockPrivate *>(quintptr(d) + Counter);
206 Q_ASSERT_X(quintptr(val) > Counter,
"QReadWriteLock::tryLockForRead()",
207 "Overflow in lock counter");
208 if (!d_ptr.testAndSetAcquire(d, val, d))
213 if (d == dummyLockedForWrite) {
214 if (timeout.hasExpired())
218 auto val = QReadWriteLockPrivate::allocate();
219 val->writerCount = 1;
220 if (!d_ptr.testAndSetOrdered(d, val, d)) {
221 val->writerCount = 0;
227 Q_ASSERT(!isUncontendedLocked(d));
229 d = d_ptr.loadAcquire();
230 if (!d || isUncontendedLocked(d))
234 return d->recursiveLockForRead(timeout);
236 auto lock = qt_unique_lock(d->mutex);
237 if (d != d_ptr.loadRelaxed()) {
244 d = d_ptr.loadAcquire();
247 return d->lockForRead(lock, timeout);
252
253
254
255
256
257
258
259
260
261
262
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
305QBasicReadWriteLock::contendedTryLockForWrite(QDeadlineTimer timeout,
void *dd)
307 auto d =
static_cast<QReadWriteLockPrivate *>(dd);
311 if (fastTryLock(d_ptr, dummyLockedForWrite, d))
316 if (isUncontendedLocked(d)) {
317 if (timeout.hasExpired())
321 auto val = QReadWriteLockPrivate::allocate();
322 if (d == dummyLockedForWrite)
323 val->writerCount = 1;
325 val->readerCount = (quintptr(d) >> 4) + 1;
326 if (!d_ptr.testAndSetOrdered(d, val, d)) {
327 val->writerCount = val->readerCount = 0;
333 Q_ASSERT(!isUncontendedLocked(d));
335 d = d_ptr.loadAcquire();
336 if (!d || isUncontendedLocked(d))
340 return d->recursiveLockForWrite(timeout);
342 auto lock = qt_unique_lock(d->mutex);
343 if (d != d_ptr.loadRelaxed()) {
347 d = d_ptr.loadAcquire();
350 return d->lockForWrite(lock, timeout);
355
356
357
358
359
360
361
362
364void QBasicReadWriteLock::contendedUnlock(
void *dd)
366 auto d =
static_cast<QReadWriteLockPrivate *>(dd);
368 Q_ASSERT_X(d,
"QReadWriteLock::unlock()",
"Cannot unlock an unlocked lock");
371 if (quintptr(d) <= 2) {
372 if (!d_ptr.testAndSetOrdered(d,
nullptr, d))
377 if ((quintptr(d) & StateMask) == StateLockedForRead) {
378 Q_ASSERT(quintptr(d) > Counter);
380 auto val =
reinterpret_cast<QReadWriteLockPrivate *>(quintptr(d) - (1U<<4));
381 if (!d_ptr.testAndSetOrdered(d, val, d))
386 Q_ASSERT(!isUncontendedLocked(d));
389 d->recursiveUnlock();
393 const auto lock = qt_scoped_lock(d->mutex);
394 if (d->writerCount) {
395 Q_ASSERT(d->writerCount == 1);
396 Q_ASSERT(d->readerCount == 0);
399 Q_ASSERT(d->readerCount > 0);
401 if (d->readerCount > 0)
405 if (d->waitingReaders || d->waitingWriters) {
408 Q_ASSERT(d_ptr.loadRelaxed() == d);
409 d_ptr.storeRelease(
nullptr);
418 Q_ASSERT(!mutex.try_lock());
421 if (timeout.hasExpired())
423 if (!timeout.isForever()) {
425 readerCond.wait_until(lock, timeout.deadline<steady_clock>());
439 Q_ASSERT(!mutex.try_lock());
442 if (timeout.hasExpired()) {
450 if (!timeout.isForever()) {
452 writerCond.wait_until(lock, timeout.deadline<steady_clock>());
468 Q_ASSERT(!mutex.try_lock());
483 auto lock = qt_unique_lock(mutex);
485 Qt::HANDLE self = QThread::currentThreadId();
487 auto it = std::find_if(currentReaders.begin(), currentReaders.end(),
489 if (it != currentReaders.end()) {
490 ++it->recursionLevel;
494 if (!lockForRead(lock, timeout))
498 currentReaders.append(std::move(r));
505 auto lock = qt_unique_lock(mutex);
507 Qt::HANDLE self = QThread::currentThreadId();
508 if (currentWriter == self) {
513 if (!lockForWrite(lock, timeout))
516 currentWriter = self;
523 auto lock = qt_unique_lock(mutex);
525 Qt::HANDLE self = QThread::currentThreadId();
526 if (self == currentWriter) {
529 currentWriter =
nullptr;
531 auto it = std::find_if(currentReaders.begin(), currentReaders.end(),
533 if (it == currentReaders.end()) {
534 qWarning(
"QReadWriteLock::unlock: unlocking from a thread that did not lock");
537 if (--it->recursionLevel <= 0) {
538 currentReaders.erase(it);
551struct QReadWriteLockFreeListConstants : QFreeListDefaultConstants
553 enum { BlockCount = 4, MaxIndex=0xffff };
554 static const int Sizes[BlockCount];
557 QReadWriteLockFreeListConstants::Sizes[QReadWriteLockFreeListConstants::BlockCount] = {
558 16, 128, 1024, QReadWriteLockFreeListConstants::MaxIndex - (16 + 128 + 1024)
561typedef QFreeList<QReadWriteLockPrivate, QReadWriteLockFreeListConstants> QReadWriteLockFreeList;
562Q_GLOBAL_STATIC(QReadWriteLockFreeList, qrwl_freelist);
567 int i = qrwl_freelist->next();
579 qrwl_freelist->release(id);
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
616
617
618
619
620
621
622
623
626
627
628
629
630
631
632
635
636
637
638
639
640
643
644
645
646
647
648
651
652
653
654
655
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
691
692
693
694
695
696
697
698
701
702
703
704
705
706
707
710
711
712
713
714
715
718
719
720
721
722
723
726
727
728
729
730
std::condition_variable readerCond
bool lockForRead(std::unique_lock< std::mutex > &lock, QDeadlineTimer timeout)
bool lockForWrite(std::unique_lock< std::mutex > &lock, QDeadlineTimer timeout)
bool recursiveLockForRead(QDeadlineTimer timeout)
bool recursiveLockForWrite(QDeadlineTimer timeout)
static QReadWriteLockPrivate * allocate()
std::condition_variable writerCond
static Q_ALWAYS_INLINE bool fastTryLock(QAtomicPointer< QReadWriteLockPrivate > &d_ptr, QReadWriteLockPrivate *dummyValue, QReadWriteLockPrivate *&d)
static auto handleEquals(Qt::HANDLE handle)