summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp24
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h7
-rw-r--r--src/webchannel/qwebchannel.cpp5
-rw-r--r--tests/auto/webchannel/tst_webchannel.cpp53
-rw-r--r--tests/auto/webchannel/tst_webchannel.h2
5 files changed, 90 insertions, 1 deletions
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index a0c3af7..8fd8e4f 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -449,6 +449,29 @@ void QMetaObjectPublisher::objectDestroyed(const QObject *object)
pendingPropertyUpdates.remove(object);
}
+void QMetaObjectPublisher::transportRemoved(QWebChannelAbstractTransport *transport)
+{
+ auto it = transportedWrappedObjects.find(transport);
+ // It is not allowed to modify a container while iterating over it. So save
+ // objects which should be removed and call objectDestroyed() on them later.
+ QVector<QObject*> objectsForDeletion;
+ while (it != transportedWrappedObjects.end() && it.key() == transport) {
+ if (wrappedObjects.contains(it.value())) {
+ QVector<QWebChannelAbstractTransport*> &transports = wrappedObjects[it.value()].transports;
+ transports.removeOne(transport);
+ if (transports.isEmpty())
+ objectsForDeletion.append(wrappedObjects[it.value()].object);
+ }
+
+ it++;
+ }
+
+ transportedWrappedObjects.remove(transport);
+
+ foreach (QObject *obj, objectsForDeletion)
+ objectDestroyed(obj);
+}
+
// NOTE: transport can be a nullptr
// in such a case, we need to ensure that the property is registered to
// the target transports of the parentObjectId
@@ -480,6 +503,7 @@ QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelA
oi.transports = webChannel->d_func()->transports;
}
wrappedObjects.insert(id, oi);
+ transportedWrappedObjects.insert(transport, id);
initializePropertyUpdates(object, classInfo);
} else if (wrappedObjects.contains(id)) {
diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h
index c48fc84..fe75656 100644
--- a/src/webchannel/qmetaobjectpublisher_p.h
+++ b/src/webchannel/qmetaobjectpublisher_p.h
@@ -168,6 +168,11 @@ public:
void objectDestroyed(const QObject *object);
/**
+ * Remove wrapped objects which last transport relation is with the passed transport object.
+ */
+ void transportRemoved(QWebChannelAbstractTransport *transport);
+
+ /**
* Given a QVariant containing a QObject*, wrap the object and register for property updates
* return the objects class information.
*
@@ -248,6 +253,8 @@ private:
// Map of objects wrapped from invocation returns
QHash<QString, ObjectInfo> wrappedObjects;
+ // Map of transports to wrapped object ids
+ QMultiHash<QWebChannelAbstractTransport*, QString> transportedWrappedObjects;
// Map of objects to maps of signal indices to a set of all their property indices.
// The last value is a set as a signal can be the notify signal of multiple properties.
diff --git a/src/webchannel/qwebchannel.cpp b/src/webchannel/qwebchannel.cpp
index b7c62e9..7a63af9 100644
--- a/src/webchannel/qwebchannel.cpp
+++ b/src/webchannel/qwebchannel.cpp
@@ -81,9 +81,11 @@ QT_BEGIN_NAMESPACE
*/
void QWebChannelPrivate::_q_transportDestroyed(QObject *object)
{
- const int idx = transports.indexOf(static_cast<QWebChannelAbstractTransport*>(object));
+ QWebChannelAbstractTransport *transport = static_cast<QWebChannelAbstractTransport*>(object);
+ const int idx = transports.indexOf(transport);
if (idx != -1) {
transports.remove(idx);
+ publisher->transportRemoved(transport);
}
}
@@ -252,6 +254,7 @@ void QWebChannel::disconnectFrom(QWebChannelAbstractTransport *transport)
disconnect(transport, 0, this, 0);
disconnect(transport, 0, d->publisher, 0);
d->transports.remove(idx);
+ d->publisher->transportRemoved(transport);
}
}
diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp
index 7e8e5f5..9531c6f 100644
--- a/tests/auto/webchannel/tst_webchannel.cpp
+++ b/tests/auto/webchannel/tst_webchannel.cpp
@@ -455,6 +455,28 @@ void TestWebChannel::testWrapRegisteredObject()
QCOMPARE(obj.objectName(), returnedId);
}
+void TestWebChannel::testRemoveUnusedTransports()
+{
+ QWebChannel channel;
+ DummyTransport *dummyTransport = new DummyTransport(this);
+ TestObject obj;
+
+ channel.connectTo(dummyTransport);
+ channel.d_func()->publisher->initializeClient(dummyTransport);
+
+ QMetaObjectPublisher *pub = channel.d_func()->publisher;
+ pub->wrapResult(QVariant::fromValue(&obj), dummyTransport);
+
+ QCOMPARE(pub->wrappedObjects.size(), 1);
+ QCOMPARE(pub->registeredObjectIds.size(), 1);
+
+ channel.disconnectFrom(dummyTransport);
+ delete dummyTransport;
+
+ QCOMPARE(pub->wrappedObjects.size(), 0);
+ QCOMPARE(pub->registeredObjectIds.size(), 0);
+}
+
void TestWebChannel::testInfiniteRecursion()
{
QWebChannel channel;
@@ -550,6 +572,37 @@ void TestWebChannel::benchRegisterObjects()
channel.registerObjects(objects);
}
}
+
+void TestWebChannel::benchRemoveTransport()
+{
+ QWebChannel channel;
+ QList<DummyTransport*> dummyTransports;
+ for (int i = 500; i > 0; i--)
+ dummyTransports.append(new DummyTransport(this));
+
+ QList<QSharedPointer<TestObject>> objs;
+ QMetaObjectPublisher *pub = channel.d_func()->publisher;
+
+ foreach (DummyTransport *transport, dummyTransports) {
+ channel.connectTo(transport);
+ channel.d_func()->publisher->initializeClient(transport);
+
+ /* 30 objects per transport */
+ for (int i = 30; i > 0; i--) {
+ QSharedPointer<TestObject> obj = QSharedPointer<TestObject>::create();
+ objs.append(obj);
+ pub->wrapResult(QVariant::fromValue(obj.data()), transport);
+ }
+ }
+
+ QBENCHMARK_ONCE {
+ for (auto transport : dummyTransports)
+ pub->transportRemoved(transport);
+ }
+
+ qDeleteAll(dummyTransports);
+}
+
#ifdef WEBCHANNEL_TESTS_CAN_USE_JS_ENGINE
class SubclassedTestObject : public TestObject
diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h
index 98733dc..0d2fe55 100644
--- a/tests/auto/webchannel/tst_webchannel.h
+++ b/tests/auto/webchannel/tst_webchannel.h
@@ -232,12 +232,14 @@ private slots:
void testInvokeMethodConversion();
void testDisconnect();
void testWrapRegisteredObject();
+ void testRemoveUnusedTransports();
void testInfiniteRecursion();
void benchClassInfo();
void benchInitializeClients();
void benchPropertyUpdates();
void benchRegisterObjects();
+ void benchRemoveTransport();
void qtbug46548_overriddenProperties();