QProperty: Avoid TLS lookup if we are in the same thread

If the QBindingStatus we receive from the QObject is from the thread
which is currently running, we do not need to refetch the thread local;
the reason we refetched the thread_local was after all only to guard
against the case where a QObject's property gets read in a different
thread.
To determine whether we are in the same thread, we can store the thread
id in the thread_local structure. Currently, it only gets initialized
for the main thread in QCoreApplication (as bindings are mostly used
there).
At a later point, we could either expose initBindingStatusThreadId, or
call the function when a QThread gets started.

Pick-to: 6.2
Change-Id: Id8eb803973bb083abfab83a62bfccc9e88a4e542
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Fabian Kosmale 2021-06-25 11:06:30 +02:00
parent fa8cffa4c9
commit 460700f773
4 changed files with 18 additions and 1 deletions

View File

@ -47,6 +47,7 @@
#include "qeventloop.h"
#endif
#include "qmetaobject.h"
#include <private/qproperty_p.h>
#include "qcorecmdlineargs_p.h"
#include <qdatastream.h>
#include <qdebug.h>
@ -861,6 +862,7 @@ void QCoreApplicationPrivate::init()
qt_call_pre_routines();
qt_startup_hook();
#ifndef QT_BOOTSTRAPPED
QtPrivate::initBindingStatusThreadId();
if (Q_UNLIKELY(qtHookData[QHooks::Startup]))
reinterpret_cast<QHooks::StartupCallback>(qtHookData[QHooks::Startup])();
#endif

View File

@ -43,6 +43,7 @@
#include <qscopedvaluerollback.h>
#include <QScopeGuard>
#include <QtCore/qloggingcategory.h>
#include <QThread>
QT_BEGIN_NAMESPACE
@ -2184,7 +2185,12 @@ void QBindingStorage::registerDependency_helper(const QUntypedPropertyData *data
Q_ASSERT(bindingStatus);
// Use ::bindingStatus to get the binding from TLS. This is required, so that reads from
// another thread do not register as dependencies
auto *currentBinding = QT_PREPEND_NAMESPACE(bindingStatus).currentlyEvaluatingBinding;
const bool threadMatches = (QThread::currentThreadId() == bindingStatus->threadId);
QtPrivate::BindingEvaluationState *currentBinding;
if (Q_LIKELY(threadMatches))
currentBinding = bindingStatus->currentlyEvaluatingBinding;
else
currentBinding = QT_PREPEND_NAMESPACE(bindingStatus).currentlyEvaluatingBinding;
QUntypedPropertyData *dd = const_cast<QUntypedPropertyData *>(data);
auto storage = QBindingStoragePrivate(d).get(dd, /*create=*/ currentBinding != nullptr);
if (!storage)
@ -2205,6 +2211,13 @@ QPropertyBindingData *QBindingStorage::bindingData_helper(QUntypedPropertyData *
namespace QtPrivate {
void initBindingStatusThreadId()
{
bindingStatus.threadId = QThread::currentThreadId();
}
BindingEvaluationState *suspendCurrentBindingStatus()
{
auto ret = bindingStatus.currentlyEvaluatingBinding;

View File

@ -943,6 +943,7 @@ struct QBindingStatus
{
QtPrivate::BindingEvaluationState *currentlyEvaluatingBinding = nullptr;
QtPrivate::CompatPropertySafePoint *currentCompatProperty = nullptr;
Qt::HANDLE threadId = nullptr;
};
struct QBindingStorageData;

View File

@ -391,6 +391,7 @@ inline QPropertyObserverPointer QPropertyBindingDataPointer::firstObserver() con
namespace QtPrivate {
Q_CORE_EXPORT bool isPropertyInBindingWrapper(const QUntypedPropertyData *property);
void Q_CORE_EXPORT initBindingStatusThreadId();
}
template<typename Class, typename T, auto Offset, auto Setter, auto Signal=nullptr>