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 (QReadWriteLockPrivate *dd = d_ptr.loadAcquire(); d != dd) {
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 (QReadWriteLockPrivate *dd = d_ptr.loadAcquire(); d != dd) {
350 return d->lockForWrite(lock, timeout);
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369bool QBasicReadWriteLock::isContendedLockForRead(
const void *dd)
371 auto d =
static_cast<
const QReadWriteLockPrivate *>(dd);
373 Q_ASSERT_X(!isUncontendedLocked(d),
"QReadWriteLock::unlock",
"Not in a contended or recursive lock");
376 return d->writerCount == 0;
380
381
382
383
384
385
386
387
389void QBasicReadWriteLock::contendedUnlock(
void *dd)
391 auto d =
static_cast<QReadWriteLockPrivate *>(dd);
393 Q_ASSERT_X(d,
"QReadWriteLock::unlock()",
"Cannot unlock an unlocked lock");
396 if (quintptr(d) <= 2) {
397 if (!d_ptr.testAndSetOrdered(d,
nullptr, d))
402 if ((quintptr(d) & StateMask) == StateLockedForRead) {
403 Q_ASSERT(quintptr(d) > Counter);
405 auto val =
reinterpret_cast<QReadWriteLockPrivate *>(quintptr(d) - (1U<<4));
406 if (!d_ptr.testAndSetOrdered(d, val, d))
411 Q_ASSERT(!isUncontendedLocked(d));
414 d->recursiveUnlock();
418 const auto lock = qt_scoped_lock(d->mutex);
419 if (d->writerCount) {
420 Q_ASSERT(d->writerCount == 1);
421 Q_ASSERT(d->readerCount == 0);
424 Q_ASSERT(d->readerCount > 0);
426 if (d->readerCount > 0)
430 if (d->waitingReaders || d->waitingWriters) {
433 Q_ASSERT(d_ptr.loadRelaxed() == d);
434 d_ptr.storeRelease(
nullptr);
443 Q_ASSERT(!mutex.try_lock());
446 if (timeout.hasExpired())
448 if (!timeout.isForever()) {
450 readerCond.wait_until(lock, timeout.deadline<steady_clock>());
464 Q_ASSERT(!mutex.try_lock());
467 if (timeout.hasExpired()) {
475 if (!timeout.isForever()) {
477 writerCond.wait_until(lock, timeout.deadline<steady_clock>());
493 Q_ASSERT(!mutex.try_lock());
508 auto lock = qt_unique_lock(mutex);
510 Qt::HANDLE self = QThread::currentThreadId();
512 auto it =
std::find_if(currentReaders.begin(), currentReaders.end(),
514 if (it != currentReaders.end()) {
515 ++it->recursionLevel;
519 if (!lockForRead(lock, timeout))
523 currentReaders.append(std::move(r));
530 auto lock = qt_unique_lock(mutex);
532 Qt::HANDLE self = QThread::currentThreadId();
533 if (currentWriter == self) {
538 if (!lockForWrite(lock, timeout))
541 currentWriter = self;
548 auto lock = qt_unique_lock(mutex);
550 Qt::HANDLE self = QThread::currentThreadId();
551 if (self == currentWriter) {
554 currentWriter =
nullptr;
556 auto it =
std::find_if(currentReaders.begin(), currentReaders.end(),
558 if (it == currentReaders.end()) {
559 qWarning(
"QReadWriteLock::unlock: unlocking from a thread that did not lock");
562 if (--it->recursionLevel <= 0) {
563 currentReaders.erase(it);
576struct QReadWriteLockFreeListConstants : QFreeListDefaultConstants
578 enum { BlockCount = 4, MaxIndex=0xffff };
579 static const int Sizes[BlockCount];
582 QReadWriteLockFreeListConstants::Sizes[QReadWriteLockFreeListConstants::BlockCount] = {
583 16, 128, 1024, QReadWriteLockFreeListConstants::MaxIndex - (16 + 128 + 1024)
586typedef QFreeList<QReadWriteLockPrivate, QReadWriteLockFreeListConstants> QReadWriteLockFreeList;
587Q_GLOBAL_STATIC(QReadWriteLockFreeList, qrwl_freelist);
592 int i = qrwl_freelist->next();
604 qrwl_freelist->release(id);
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
635
636
637
638
641
642
643
644
645
646
647
648
651
652
653
654
655
656
657
660
661
662
663
664
665
668
669
670
671
672
673
676
677
678
679
680
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
710
711
712
713
716
717
718
719
720
721
722
723
726
727
728
729
730
731
732
735
736
737
738
739
740
743
744
745
746
747
748
751
752
753
754
755
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)