Optimize QSharedPointer::getAndRef with the three-operand testAndSet

Originally QAtomicPointer didn't have the three-operand version,
resulting in code like:
  if (!atomic.testAndSetXxx(expected, newvalue))
       expected = atomic.load();

The three-operand version gives us the current value of the atomic in
case the test failed and it's free in all architectures, unlike the
extra load.

I have to use testAndSetOrdered here because I need the failing load to
use the Acquire memory order, even though that has an extra Acquire for
the successful case we don't need. QAtomicPointer does not have
testAndSetReleaseAcquire.

Change-Id: I1bd327aeaf73421a8ec5fffd1560fe30d3bfd9b8
Reviewed-by: Romain Pokrzywka <romain.pokrzywka@gmail.com>
Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@qt.io>
This commit is contained in:
Thiago Macieira 2018-10-25 16:35:58 -07:00
parent 4447db4465
commit dba6067670

View File

@ -1383,15 +1383,18 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge
ExternalRefCountData *x = new ExternalRefCountData(Qt::Uninitialized);
x->strongref.store(-1);
x->weakref.store(2); // the QWeakPointer that called us plus the QObject itself
if (!d->sharedRefcount.testAndSetRelease(0, x)) {
ExternalRefCountData *ret;
if (d->sharedRefcount.testAndSetOrdered(nullptr, x, ret)) { // ought to be release+acquire; this is acq_rel+acquire
ret = x;
} else {
// ~ExternalRefCountData has a Q_ASSERT, so we use this trick to
// only execute this if Q_ASSERTs are enabled
Q_ASSERT((x->weakref.store(0), true));
delete x;
x = d->sharedRefcount.loadAcquire();
x->weakref.ref();
ret->weakref.ref();
}
return x;
return ret;
}
/**