summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorWeng Xuetian <wengxt@gmail.com>2016-03-05 12:23:21 -0800
committerWeng Xuetian <wengxt@gmail.com>2016-04-08 16:16:14 +0000
commitb77ef8a7e6e4104067d52824e29eadc8c66f5929 (patch)
tree88af4f77c5a7517095705fc7c088b0ad150bb8b9 /src
parentb0bfe8de68a27de34b9493e7d5263cad1e5823c9 (diff)
QtDBus: clean up signal hooks and object tree in closeConnection
If a QObject is added or passed as receiver to QDBusConnection::connect() and it is managed by Q_GLOBAL_STATIC or similar mechanism, it is possible that when that its destructor is called after the dbus daemon thread ends. In that case, QObject::destroyed connected via Qt::BlockingQueuedConnection to QDBusConnectionPrivate will cause dead lock since the thread is no longer processing events. Task-number: QTBUG-51648 Change-Id: I1a1810a6d6d0234af0269d5f3fc1f54101bf1547 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src')
-rw-r--r--src/dbus/qdbusconnection_p.h1
-rw-r--r--src/dbus/qdbusintegrator.cpp26
2 files changed, 26 insertions, 1 deletions
diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h
index c77daf7ee1..565eb832f2 100644
--- a/src/dbus/qdbusconnection_p.h
+++ b/src/dbus/qdbusconnection_p.h
@@ -254,6 +254,7 @@ private:
const QVector<int> &metaTypes, int slotIdx);
SignalHookHash::Iterator removeSignalHookNoLock(SignalHookHash::Iterator it);
+ void disconnectObjectTree(ObjectTreeNode &node);
bool isServiceRegisteredByThread(const QString &serviceName);
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index 478a2c4a05..3be775db82 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -1050,7 +1050,6 @@ QDBusConnectionPrivate::~QDBusConnectionPrivate()
qPrintable(name));
closeConnection();
- rootNode.children.clear(); // free resources
qDeleteAll(cachedMetaObjects);
if (mode == ClientMode || mode == PeerMode) {
@@ -1072,6 +1071,19 @@ QDBusConnectionPrivate::~QDBusConnectionPrivate()
}
}
+void QDBusConnectionPrivate::disconnectObjectTree(QDBusConnectionPrivate::ObjectTreeNode &haystack)
+{
+ QDBusConnectionPrivate::ObjectTreeNode::DataList::Iterator it = haystack.children.begin();
+
+ while (it != haystack.children.end()) {
+ disconnectObjectTree(*it);
+ it++;
+ }
+
+ if (haystack.obj)
+ haystack.obj->disconnect(this);
+}
+
void QDBusConnectionPrivate::closeConnection()
{
QDBusWriteLocker locker(CloseConnectionAction, this);
@@ -1095,6 +1107,18 @@ void QDBusConnectionPrivate::closeConnection()
}
qDeleteAll(pendingCalls);
+
+ // Disconnect all signals from signal hooks and from the object tree to
+ // avoid QObject::destroyed being sent to dbus daemon thread which has
+ // already quit.
+ SignalHookHash::iterator sit = signalHooks.begin();
+ while (sit != signalHooks.end()) {
+ sit.value().obj->disconnect(this);
+ sit++;
+ }
+
+ disconnectObjectTree(rootNode);
+ rootNode.children.clear(); // free resources
}
void QDBusConnectionPrivate::checkThread()