summaryrefslogtreecommitdiff
path: root/source/l/qt5/patches/qt5.qtbug-51648.patch
blob: 279839b04aa297747207b51c8b17f16301600df6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
From b024fbe83863fc57364a52c717d5b43d654bdb5d Mon Sep 17 00:00:00 2001
From: Weng Xuetian <wengxt@gmail.com>
Date: Sat, 5 Mar 2016 12:23:21 -0800
Subject: [PATCH] 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
---
 src/dbus/qdbusconnection_p.h |  1 +
 src/dbus/qdbusintegrator.cpp | 28 +++++++++++++++++++++++++++-
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h
index c77daf7..565eb83 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 cd44861..a3cd47b 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -1030,7 +1030,6 @@ QDBusConnectionPrivate::~QDBusConnectionPrivate()
                  qPrintable(name));
 
     closeConnection();
-    rootNode.children.clear();  // free resources
     qDeleteAll(cachedMetaObjects);
 
     if (mode == ClientMode || mode == PeerMode) {
@@ -1052,6 +1051,20 @@ 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);
@@ -1075,6 +1088,19 @@ void QDBusConnectionPrivate::closeConnection()
     }
 
     qDeleteAll(pendingCalls);
+
+    // clean up all signal hook and object tree, to avoid QObject::destroyed
+    // being activated to dbus daemon thread which already quits.
+    // dbus connection is already closed, so there is nothing we could do be clean
+    // up everything here.
+    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()
-- 
2.7.1