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>
This commit is contained in:
Weng Xuetian 2016-03-05 12:23:21 -08:00
parent b0bfe8de68
commit b77ef8a7e6
2 changed files with 26 additions and 1 deletions

View File

@ -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);

View File

@ -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()