Merge lp:~gerboland/unity8/async-dbus-dashcomm into lp:unity8

Proposed by Gerry Boland
Status: Merged
Approved by: Michael Zanetti
Approved revision: 1523
Merged at revision: 1546
Proposed branch: lp:~gerboland/unity8/async-dbus-dashcomm
Merge into: lp:unity8
Diff against target: 187 lines (+64/-14)
4 files modified
plugins/Unity/DashCommunicator/dashconnection.cpp (+30/-0)
plugins/Unity/DashCommunicator/dashconnection.h (+4/-1)
src/libunity8-private/abstractdbusservicemonitor.cpp (+21/-8)
src/libunity8-private/abstractdbusservicemonitor.h (+9/-5)
To merge this branch: bzr merge lp:~gerboland/unity8/async-dbus-dashcomm
Reviewer Review Type Date Requested Status
Michael Zanetti (community) Approve
PS Jenkins bot (community) continuous-integration Needs Fixing
Review via email: mp+244892@code.launchpad.net

Commit message

DashCommunicator: replace QDBusInterface with a non-blocking simplification which does not introspect the service on creation

Description of the change

QDBusInterface on creation introspects the service it is pointed to. This introspection is performed on the GUI thread, no matter what thread QDBusInterface is created on - see the moveToThread in qtbase/src/dbus/qdbusconnection.cpp.

Therefore should the service being introspected is busy at the time, the GUI thread is blocked, which is a bad thing. This isn't too easily noticed today with unity8 on startup, but it is there (Greeter not reacting quickly).

It is much easier to notice if you ssh into the phone and do "stop unity8-dash; start unity-dash" and just watch the spinner as dash is starting. It can be seen to hang for 500ms+ - that's the entire shell GUI blocked for over 1/2 a second.

What do we loose not using QDbusInterface directly? Mainly the ability to connect to dbus signals from the service. QDbusInterface creates a meta object which represents the service's interface, and translates meta object calls to dbus calls. As DashCommunicator just calls dbus methods, this can be handled without any meta object bits, so the QDBusAbstractInterface has enough to do this.

 * Are there any related MPs required for this MP to build/function as expected? Please list.
N
 * Did you perform an exploratory manual test run of your code change and any related functionality?
Y on N7 & desktop
 * Did you make sure that your branch does not contain spurious tags?
Y
 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
 * If you changed the UI, has there been a design review?
N/A

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Lorn Potter (lorn-potter) wrote :

This change looks ok to me.

Revision history for this message
MichaƂ Sawicz (saviq) wrote :

Typo.

1523. By Gerry Boland

Fix typo

Revision history for this message
Gerry Boland (gerboland) wrote :

Typo fixed

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?

yes

 * Did CI run pass? If not, please explain why.

no, but it's a known failure in trunk

 * Did you make sure that the branch does not contain spurious tags?

yes

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/Unity/DashCommunicator/dashconnection.cpp'
2--- plugins/Unity/DashCommunicator/dashconnection.cpp 2014-10-20 15:52:56 +0000
3+++ plugins/Unity/DashCommunicator/dashconnection.cpp 2015-01-05 11:13:21 +0000
4@@ -19,12 +19,42 @@
5 #include <QDBusInterface>
6 #include <QDBusPendingCall>
7
8+/* The default implementation of AbstractDBusServiceMonitor creates a QDBusInterface when the service
9+ * appears on the bus.
10+ *
11+ * On construction QDBusInterface synchronously introspects the service, which will block the GUI
12+ * thread of this process if the service is busy. QDBusAbstractInterface does not perform this
13+ * introspection, so let's subclass that and avoid the blocking scenario.
14+ *
15+ * However we lose Qt's wrapping of the DBus service with a MetaObject, with the result that we
16+ * cannot easily connect to DBus signals with the usual connect() calls. So this approach only
17+ * suited to push communication with the DBus service.
18+ */
19+class AsyncDBusInterface : public QDBusAbstractInterface
20+{
21+public:
22+ AsyncDBusInterface(const QString &service, const QString &path,
23+ const QString &interface, const QDBusConnection &connection,
24+ QObject *parent = 0)
25+ : QDBusAbstractInterface(service, path, interface.toLatin1().data(), connection, parent)
26+ {}
27+ ~AsyncDBusInterface() = default;
28+};
29+
30+
31 DashConnection::DashConnection(const QString &service, const QString &path, const QString &interface, QObject *parent):
32 AbstractDBusServiceMonitor(service, path, interface, SessionBus, parent)
33 {
34
35 }
36
37+/* Override the default implementation to create a non-blocking DBus interface (see note above). */
38+QDBusAbstractInterface* DashConnection::createInterface(const QString &service, const QString &path,
39+ const QString &interface, const QDBusConnection &connection)
40+{
41+ return new AsyncDBusInterface(service, path, interface, connection);
42+}
43+
44 void DashConnection::setCurrentScope(int index, bool animate, bool isSwipe)
45 {
46 if (dbusInterface()) {
47
48=== modified file 'plugins/Unity/DashCommunicator/dashconnection.h'
49--- plugins/Unity/DashCommunicator/dashconnection.h 2014-10-20 15:52:56 +0000
50+++ plugins/Unity/DashCommunicator/dashconnection.h 2015-01-05 11:13:21 +0000
51@@ -20,7 +20,6 @@
52 // local
53 #include "abstractdbusservicemonitor.h"
54
55-
56 class DashConnection: public AbstractDBusServiceMonitor
57 {
58 Q_OBJECT
59@@ -29,6 +28,10 @@
60
61 public Q_SLOTS:
62 void setCurrentScope(int index, bool animate, bool isSwipe);
63+
64+private:
65+ QDBusAbstractInterface* createInterface(const QString &service, const QString &path,
66+ const QString &interface, const QDBusConnection &connection) override;
67 };
68
69 #endif
70
71=== modified file 'src/libunity8-private/abstractdbusservicemonitor.cpp'
72--- src/libunity8-private/abstractdbusservicemonitor.cpp 2014-09-29 09:56:41 +0000
73+++ src/libunity8-private/abstractdbusservicemonitor.cpp 2015-01-05 11:13:21 +0000
74@@ -32,19 +32,20 @@
75 , m_service(service)
76 , m_path(path)
77 , m_interface(interface)
78+ , m_bus(bus)
79 , m_watcher(new QDBusServiceWatcher(service,
80 (bus == SystemBus) ? QDBusConnection::systemBus()
81 : QDBusConnection::sessionBus()))
82 , m_dbusInterface(nullptr)
83 {
84- connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, &AbstractDBusServiceMonitor::createInterface);
85- connect(m_watcher, &QDBusServiceWatcher::serviceUnregistered, this, &AbstractDBusServiceMonitor::destroyInterface);
86+ connect(m_watcher, &QDBusServiceWatcher::serviceRegistered, this, &AbstractDBusServiceMonitor::onServiceRegistered);
87+ connect(m_watcher, &QDBusServiceWatcher::serviceUnregistered, this, &AbstractDBusServiceMonitor::onServiceUnregistered);
88
89 // Connect to the service if it's up already
90 QDBusConnectionInterface* sessionBus = QDBusConnection::sessionBus().interface();
91 QDBusReply<bool> reply = sessionBus->isServiceRegistered(m_service);
92 if (reply.isValid() && reply.value()) {
93- createInterface(m_service);
94+ onServiceRegistered(m_service);
95 }
96 }
97
98@@ -54,19 +55,31 @@
99 delete m_dbusInterface;
100 }
101
102-void AbstractDBusServiceMonitor::createInterface(const QString &)
103+void AbstractDBusServiceMonitor::onServiceRegistered(const QString &)
104 {
105 if (m_dbusInterface != nullptr) {
106 delete m_dbusInterface;
107 m_dbusInterface = nullptr;
108 }
109
110- m_dbusInterface = new QDBusInterface(m_service, m_path, m_interface,
111- QDBusConnection::sessionBus());
112+ m_dbusInterface = createInterface(m_service, m_path, m_interface,
113+ (m_bus == SystemBus) ? QDBusConnection::systemBus()
114+ : QDBusConnection::sessionBus());
115 Q_EMIT serviceAvailableChanged(true);
116 }
117
118-void AbstractDBusServiceMonitor::destroyInterface(const QString &)
119+/*
120+ * Default implementation creates a QDBusInterface. This performs blocking introspection of the
121+ * service at initialization, which may be undesirable if the service is slow/blocked.
122+ */
123+QDBusAbstractInterface*
124+AbstractDBusServiceMonitor::createInterface(const QString &service, const QString &path,
125+ const QString &interface, const QDBusConnection &connection)
126+{
127+ return new QDBusInterface(service, path, interface, connection);
128+}
129+
130+void AbstractDBusServiceMonitor::onServiceUnregistered(const QString &)
131 {
132 if (m_dbusInterface != nullptr) {
133 delete m_dbusInterface;
134@@ -76,7 +89,7 @@
135 Q_EMIT serviceAvailableChanged(false);
136 }
137
138-QDBusInterface* AbstractDBusServiceMonitor::dbusInterface() const
139+QDBusAbstractInterface* AbstractDBusServiceMonitor::dbusInterface() const
140 {
141 return m_dbusInterface;
142 }
143
144=== modified file 'src/libunity8-private/abstractdbusservicemonitor.h'
145--- src/libunity8-private/abstractdbusservicemonitor.h 2014-09-29 09:43:18 +0000
146+++ src/libunity8-private/abstractdbusservicemonitor.h 2015-01-05 11:13:21 +0000
147@@ -24,7 +24,7 @@
148 #include <QString>
149 #include <QDBusConnection>
150
151-class QDBusInterface;
152+class QDBusAbstractInterface;
153 class QDBusServiceWatcher;
154
155 class Q_DECL_EXPORT AbstractDBusServiceMonitor : public QObject
156@@ -44,7 +44,7 @@
157 QObject *parent = 0);
158 ~AbstractDBusServiceMonitor();
159
160- QDBusInterface* dbusInterface() const;
161+ QDBusAbstractInterface* dbusInterface() const;
162
163 bool serviceAvailable() const;
164
165@@ -52,15 +52,19 @@
166 void serviceAvailableChanged(bool available);
167
168 private Q_SLOTS:
169- void createInterface(const QString &service);
170- void destroyInterface(const QString &service);
171+ void onServiceRegistered(const QString &service);
172+ void onServiceUnregistered(const QString &service);
173
174 protected:
175+ virtual QDBusAbstractInterface* createInterface(const QString &service, const QString &path,
176+ const QString &interface, const QDBusConnection &connection);
177+
178 const QString m_service;
179 const QString m_path;
180 const QString m_interface;
181+ const Bus m_bus;
182 QDBusServiceWatcher* m_watcher;
183- QDBusInterface* m_dbusInterface;
184+ QDBusAbstractInterface* m_dbusInterface;
185 };
186
187 #endif // ABSTRACTDBUSSERVICEMONITOR_H

Subscribers

People subscribed via source and target branches