Avoid misleading bindingStatus
Set it to nullptr on clear, and deal with possibly null bindingStatus. Task-number: QTBUG-101177 Task-number: QTBUG-102403 Pick-to: 6.4 Change-Id: I66cb4d505a4f7b377dc90b45ac13834fca19d399 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
parent
903bde19a4
commit
0bd2876275
@ -55,7 +55,7 @@ public:
|
|||||||
|
|
||||||
void registerDependency(const QUntypedPropertyData *data) const
|
void registerDependency(const QUntypedPropertyData *data) const
|
||||||
{
|
{
|
||||||
if (!bindingStatus->currentlyEvaluatingBinding)
|
if (!bindingStatus || !bindingStatus->currentlyEvaluatingBinding)
|
||||||
return;
|
return;
|
||||||
registerDependency_helper(data);
|
registerDependency_helper(data);
|
||||||
}
|
}
|
||||||
|
@ -1873,9 +1873,9 @@ void QObjectPrivate::moveToThread_helper()
|
|||||||
Q_Q(QObject);
|
Q_Q(QObject);
|
||||||
QEvent e(QEvent::ThreadChange);
|
QEvent e(QEvent::ThreadChange);
|
||||||
QCoreApplication::sendEvent(q, &e);
|
QCoreApplication::sendEvent(q, &e);
|
||||||
|
bindingStorage.clear();
|
||||||
for (int i = 0; i < children.size(); ++i) {
|
for (int i = 0; i < children.size(); ++i) {
|
||||||
QObject *child = children.at(i);
|
QObject *child = children.at(i);
|
||||||
child->d_func()->bindingStorage.clear();
|
|
||||||
child->d_func()->moveToThread_helper();
|
child->d_func()->moveToThread_helper();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2193,6 +2193,7 @@ void QBindingStorage::clear()
|
|||||||
{
|
{
|
||||||
QBindingStoragePrivate(d).destroy();
|
QBindingStoragePrivate(d).destroy();
|
||||||
d = nullptr;
|
d = nullptr;
|
||||||
|
bindingStatus = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QBindingStorage::registerDependency_helper(const QUntypedPropertyData *data) const
|
void QBindingStorage::registerDependency_helper(const QUntypedPropertyData *data) const
|
||||||
|
@ -442,7 +442,7 @@ class QObjectCompatProperty : public QPropertyData<T>
|
|||||||
}
|
}
|
||||||
bool inBindingWrapper(const QBindingStorage *storage) const
|
bool inBindingWrapper(const QBindingStorage *storage) const
|
||||||
{
|
{
|
||||||
return storage->bindingStatus->currentCompatProperty
|
return storage->bindingStatus && storage->bindingStatus->currentCompatProperty
|
||||||
&& QtPrivate::isPropertyInBindingWrapper(this);
|
&& QtPrivate::isPropertyInBindingWrapper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,7 +467,7 @@ public:
|
|||||||
{
|
{
|
||||||
const QBindingStorage *storage = qGetBindingStorage(owner());
|
const QBindingStorage *storage = qGetBindingStorage(owner());
|
||||||
// make sure we don't register this binding as a dependency to itself
|
// make sure we don't register this binding as a dependency to itself
|
||||||
if (storage->bindingStatus->currentlyEvaluatingBinding && !inBindingWrapper(storage))
|
if (storage->bindingStatus && storage->bindingStatus->currentlyEvaluatingBinding && !inBindingWrapper(storage))
|
||||||
storage->registerDependency_helper(this);
|
storage->registerDependency_helper(this);
|
||||||
return this->val;
|
return this->val;
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,7 @@ private slots:
|
|||||||
|
|
||||||
void noFakeDependencies();
|
void noFakeDependencies();
|
||||||
void threadSafety();
|
void threadSafety();
|
||||||
|
void threadSafety2();
|
||||||
|
|
||||||
void bindablePropertyWithInitialization();
|
void bindablePropertyWithInitialization();
|
||||||
void noDoubleNotification();
|
void noDoubleNotification();
|
||||||
@ -1694,7 +1695,7 @@ void tst_QProperty::threadSafety()
|
|||||||
auto child1 = new ThreadSafetyTester(obj1);
|
auto child1 = new ThreadSafetyTester(obj1);
|
||||||
obj1->moveToThread(&workerThread);
|
obj1->moveToThread(&workerThread);
|
||||||
const auto mainThreadBindingStatus = QtPrivate::getBindingStatus({});
|
const auto mainThreadBindingStatus = QtPrivate::getBindingStatus({});
|
||||||
QCOMPARE(qGetBindingStorage(child1)->status({}), mainThreadBindingStatus);
|
QCOMPARE(qGetBindingStorage(child1)->status({}), nullptr);
|
||||||
workerThread.start();
|
workerThread.start();
|
||||||
|
|
||||||
bool correctStatus = false;
|
bool correctStatus = false;
|
||||||
@ -1743,6 +1744,41 @@ void tst_QProperty::threadSafety()
|
|||||||
QCOMPARE(obj3->objectName(), "moved again");
|
QCOMPARE(obj3->objectName(), "moved again");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class QPropertyUsingThread : public QThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QPropertyUsingThread(QObject **dest, QThread *destThread) : dest(dest), destThread(destThread) {}
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
scopedObj1.reset(new ThreadSafetyTester());
|
||||||
|
scopedObj1->setObjectName("test");
|
||||||
|
QObject *child = new ThreadSafetyTester(scopedObj1.get());
|
||||||
|
child->setObjectName("child");
|
||||||
|
exec();
|
||||||
|
scopedObj1->moveToThread(destThread);
|
||||||
|
*dest = scopedObj1.release();
|
||||||
|
}
|
||||||
|
std::unique_ptr<ThreadSafetyTester> scopedObj1;
|
||||||
|
QObject **dest;
|
||||||
|
QThread *destThread;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_QProperty::threadSafety2()
|
||||||
|
{
|
||||||
|
std::unique_ptr<QObject> movedObj;
|
||||||
|
{
|
||||||
|
QObject *tmp = nullptr;
|
||||||
|
QPropertyUsingThread workerThread(&tmp, QThread::currentThread());
|
||||||
|
workerThread.start();
|
||||||
|
workerThread.quit();
|
||||||
|
workerThread.wait();
|
||||||
|
movedObj.reset(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
QCOMPARE(movedObj->objectName(), "test");
|
||||||
|
QCOMPARE(movedObj->children().first()->objectName(), "child");
|
||||||
|
}
|
||||||
|
|
||||||
struct CustomType
|
struct CustomType
|
||||||
{
|
{
|
||||||
CustomType() = default;
|
CustomType() = default;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user