Avoid TLS access for groupUpdateData

By putting the groupUpdateData pointer into the same thread local as the
binding status, we avoid having to fetch two thread_local variables.
Moreover, we can reuse the caching mechanism which we have in place for
QBindingStatus to avoid costly TLS lookups.

Pick-to: 6.2
Change-Id: Iaea515763510daab83f89b8e74f35a80965d6965
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
bb10
Fabian Kosmale 2021-06-25 15:10:23 +02:00
parent 460700f773
commit 71fea09e1a
4 changed files with 23 additions and 7 deletions

View File

@ -198,7 +198,7 @@ struct QPropertyDelayedNotifications
}
};
static thread_local QPropertyDelayedNotifications *groupUpdateData = nullptr;
static thread_local QBindingStatus bindingStatus;
/*!
\since 6.2
@ -222,6 +222,7 @@ static thread_local QPropertyDelayedNotifications *groupUpdateData = nullptr;
*/
void Qt::beginPropertyUpdateGroup()
{
QPropertyDelayedNotifications *& groupUpdateData = bindingStatus.groupUpdateData;
if (!groupUpdateData)
groupUpdateData = new QPropertyDelayedNotifications;
++groupUpdateData->ref;
@ -241,6 +242,7 @@ void Qt::beginPropertyUpdateGroup()
*/
void Qt::endPropertyUpdateGroup()
{
QPropertyDelayedNotifications *& groupUpdateData = bindingStatus.groupUpdateData;
auto *data = groupUpdateData;
Q_ASSERT(data->ref);
if (--data->ref)
@ -467,8 +469,6 @@ QPropertyBindingData::QPropertyBindingData(QPropertyBindingData &&other) : d_ptr
QPropertyBindingDataPointer::fixupAfterMove(this);
}
static thread_local QBindingStatus bindingStatus;
BindingEvaluationState::BindingEvaluationState(QPropertyBindingPrivate *binding, QBindingStatus *status)
: binding(binding)
{
@ -544,13 +544,23 @@ void QPropertyBindingData::registerWithCurrentlyEvaluatingBinding_helper(Binding
}
void QPropertyBindingData::notifyObservers(QUntypedPropertyData *propertyDataPtr) const
{
notifyObservers(propertyDataPtr, nullptr);
}
void QPropertyBindingData::notifyObservers(QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage) const
{
if (isNotificationDelayed())
return;
QPropertyBindingDataPointer d{this};
if (QPropertyObserverPointer observer = d.firstObserver()) {
auto *delay = groupUpdateData;
auto status = storage ? storage->bindingStatus : nullptr;
QPropertyDelayedNotifications *delay;
if (status && status->threadId == QThread::currentThreadId())
delay = status->groupUpdateData;
else
delay = bindingStatus.groupUpdateData;
if (delay) {
delay->addProperty(this, propertyDataPtr);
return;

View File

@ -944,8 +944,10 @@ struct QBindingStatus
QtPrivate::BindingEvaluationState *currentlyEvaluatingBinding = nullptr;
QtPrivate::CompatPropertySafePoint *currentCompatProperty = nullptr;
Qt::HANDLE threadId = nullptr;
QPropertyDelayedNotifications *groupUpdateData = nullptr;
};
struct QBindingStorageData;
class Q_CORE_EXPORT QBindingStorage
{
@ -955,6 +957,7 @@ class Q_CORE_EXPORT QBindingStorage
template<typename Class, typename T, auto Offset, auto Setter, auto Signal>
friend class QObjectCompatProperty;
friend class QObjectPrivate;
friend class QtPrivate::QPropertyBindingData;
public:
QBindingStorage();
~QBindingStorage();
@ -1184,7 +1187,7 @@ private:
void notify(const QtPrivate::QPropertyBindingData *binding)
{
if (binding)
binding->notifyObservers(this);
binding->notifyObservers(this, qGetBindingStorage(owner()));
if constexpr (HasSignal) {
if constexpr (SignalTakesValue::value)
(owner()->*Signal)(this->valueBypassingBindings());
@ -1322,7 +1325,7 @@ public:
auto *storage = const_cast<QBindingStorage *>(qGetBindingStorage(owner()));
auto bd = storage->bindingData(const_cast<QObjectComputedProperty *>(this), false);
if (bd)
bd->notifyObservers(this);
bd->notifyObservers(this, qGetBindingStorage(owner()));
}
};

View File

@ -592,7 +592,7 @@ private:
void notify(const QtPrivate::QPropertyBindingData *binding)
{
if (binding)
binding->notifyObservers(this);
binding->notifyObservers(this, qGetBindingStorage(owner()));
}
};

View File

@ -59,6 +59,8 @@
QT_BEGIN_NAMESPACE
class QBindingStorage;
namespace QtPrivate {
// QPropertyBindingPrivatePtr operates on a RefCountingMixin solely so that we can inline
// the constructor and copy constructor
@ -302,6 +304,7 @@ public:
}
void registerWithCurrentlyEvaluatingBinding() const;
void notifyObservers(QUntypedPropertyData *propertyDataPtr) const;
void notifyObservers(QUntypedPropertyData *propertyDataPtr, QBindingStorage *storage) const;
private:
/*!
\internal