Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qdbusconnectionmanager.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
6
7#include <qcoreapplication.h>
8#include <qthread.h>
9#include <qstringlist.h>
10#include <QtCore/private/qlocking_p.h>
11
12#include "qdbuserror.h"
13#include "qdbuspendingcall_p.h"
14#include "qdbusmetatype_p.h"
15
16#ifndef QT_NO_DBUS
17
19
20#ifdef Q_OS_WIN
21static void preventDllUnload();
22#endif
23
25
27{
28 static_assert(int(QDBusConnection::SessionBus) + int(QDBusConnection::SystemBus) == 1);
30
31 if (!qdbus_loadLibDBus())
32 return nullptr;
33
34 // we'll start in suspended delivery mode if we're in the main thread
35 // (the event loop will resume delivery)
36 bool suspendedDelivery = qApp && qApp->thread() == QThread::currentThread();
37
38 const auto locker = qt_scoped_lock(defaultBusMutex);
39 if (defaultBuses[type])
40 return defaultBuses[type];
41
42 QString name = QStringLiteral("qt_default_session_bus");
44 name = QStringLiteral("qt_default_system_bus");
45 return defaultBuses[type] = connectToBus(type, name, suspendedDelivery);
46}
47
48QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
49{
50 return connectionHash.value(name, nullptr);
51}
52
54{
55 const auto locker = qt_scoped_lock(mutex);
56 auto *conn = connection(name);
57 if (conn)
58 conn->ref.ref();
59 return conn;
60}
61
62void QDBusConnectionManager::removeConnection(const QString &name)
63{
64 QDBusConnectionPrivate *d = nullptr;
65 d = connectionHash.take(name);
66 if (d && !d->ref.deref())
67 d->deleteLater();
68
69 // Static objects may be keeping the connection open.
70 // However, it is harmless to have outstanding references to a connection that is
71 // closing as long as those references will be soon dropped without being used.
72
73 // ### Output a warning if connections are being used after they have been removed.
74}
75
77{
78 const auto locker = qt_scoped_lock(mutex);
79
80 for (const auto &name : names)
81 removeConnection(name);
82}
83
86{
87 const auto locker = qt_scoped_lock(mutex);
88
90 if (d && d->mode != mode)
91 return;
92 removeConnection(name);
93}
94
96{
97 // Ensure that the custom metatype registry is created before the instance
98 // of this class. This will ensure that the registry is not destroyed before
99 // the connection manager at application exit (see also QTBUG-58732). This
100 // works with compilers that use mechanism similar to atexit() to call
101 // destructurs for global statics.
103
104 moveToThread(this); // ugly, don't do this in other projects
105
106#ifdef Q_OS_WIN
107 // prevent the library from being unloaded on Windows. See comments in the function.
108 preventDllUnload();
109#endif
110 defaultBuses[0] = defaultBuses[1] = nullptr;
111 start();
112}
113
115{
116 quit();
117 wait();
118}
119
121{
122 return _q_manager();
123}
124
125Q_DBUS_EXPORT void qDBusBindToApplication();
127{
128}
129
130void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
131{
132 connectionHash[name] = c;
133 c->name = name;
134}
135
137{
138 const auto locker = qt_scoped_lock(mutex);
139 setConnection(name, c);
140}
141
143{
144 exec();
145
146 // cleanup:
147 const auto locker = qt_scoped_lock(mutex);
148 for (QDBusConnectionPrivate *d : std::as_const(connectionHash)) {
149 if (!d->ref.deref()) {
150 delete d;
151 } else {
152 d->closeConnection();
153 d->moveToThread(nullptr); // allow it to be deleted in another thread
154 }
155 }
156 connectionHash.clear();
157
158 // allow deletion from any thread without warning
159 moveToThread(nullptr);
160}
161
163 bool suspendedDelivery)
164{
166
167 QMetaObject::invokeMethod(this, &QDBusConnectionManager::doConnectToStandardBus,
169 suspendedDelivery);
170
171 if (suspendedDelivery && result && result->connection)
172 result->enableDispatchDelayed(qApp); // qApp was checked in the caller
173
174 return result;
175}
176
178{
180
181 QMetaObject::invokeMethod(this, &QDBusConnectionManager::doConnectToBus,
183
184 return result;
185}
186
188{
190
191 QMetaObject::invokeMethod(this, &QDBusConnectionManager::doConnectToPeer,
193
194 return result;
195}
196
198QDBusConnectionManager::doConnectToStandardBus(QDBusConnection::BusType type, const QString &name,
199 bool suspendedDelivery)
200{
201 const auto locker = qt_scoped_lock(mutex);
202
203 // check if the connection exists by name
205 if (d || name.isEmpty())
206 return d;
207
209 DBusConnection *c = nullptr;
211
212 switch (type) {
214 c = q_dbus_bus_get_private(DBUS_BUS_SYSTEM, error);
215 break;
217 c = q_dbus_bus_get_private(DBUS_BUS_SESSION, error);
218 break;
220 c = q_dbus_bus_get_private(DBUS_BUS_STARTER, error);
221 break;
222 }
223
224 setConnection(name, d);
225
226 // create the bus service
227 // will lock in QDBusConnectionPrivate::connectRelay()
228 d->setConnection(c, error);
229 d->createBusService();
230 if (c && suspendedDelivery)
231 d->setDispatchEnabled(false);
232
233 return d;
234}
235
236QDBusConnectionPrivate *QDBusConnectionManager::doConnectToBus(const QString &address,
237 const QString &name)
238{
239 const auto locker = qt_scoped_lock(mutex);
240
241 // check if the connection exists by name
243 if (d || name.isEmpty())
244 return d;
245
248
249 DBusConnection *c = q_dbus_connection_open_private(address.toUtf8().constData(), error);
250 if (c) {
251 // register on the bus
252 if (!q_dbus_bus_register(c, error)) {
253 q_dbus_connection_close(c);
254 q_dbus_connection_unref(c);
255 c = nullptr;
256 }
257 }
258
259 setConnection(name, d);
260
261 // create the bus service
262 // will lock in QDBusConnectionPrivate::connectRelay()
263 d->setConnection(c, error);
264 d->createBusService();
265
266 return d;
267}
268
269QDBusConnectionPrivate *QDBusConnectionManager::doConnectToPeer(const QString &address,
270 const QString &name)
271{
272 const auto locker = qt_scoped_lock(mutex);
273
274 // check if the connection exists by name
276 if (d || name.isEmpty())
277 return d;
278
281
282 DBusConnection *c = q_dbus_connection_open_private(address.toUtf8().constData(), error);
283
284 setConnection(name, d);
285 d->setPeer(c, error);
286
287 return d;
288}
289
302
304
305#include "moc_qdbusconnectionmanager_p.cpp"
306
307#ifdef Q_OS_WIN
308# include <qt_windows.h>
309
311static void preventDllUnload()
312{
313 // Thread termination is really wacky on Windows. For some reason we don't
314 // understand, exiting from the thread may try to unload the DLL. Since the
315 // QDBusConnectionManager thread runs until the DLL is unloaded, we've got
316 // a deadlock: the main thread is waiting for the manager thread to exit,
317 // but the manager thread is attempting to acquire a lock to unload the DLL.
318 //
319 // We work around the issue by preventing the unload from happening in the
320 // first place.
321 //
322 // For this trick, see the blog post titled "What is the point of FreeLibraryAndExitThread?"
323 // https://devblogs.microsoft.com/oldnewthing/20131105-00/?p=2733
324
325 static HMODULE self;
326 GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
327 GET_MODULE_HANDLE_EX_FLAG_PIN,
328 reinterpret_cast<const wchar_t *>(&self), // any address in this DLL
329 &self);
330}
332#endif
333
334#endif // QT_NO_DBUS
Connects to the accessibility dbus.
static QDBusConnectionManager * instance()
void addConnection(const QString &name, QDBusConnectionPrivate *c)
void removeConnections(const QStringList &names)
QDBusConnectionPrivate * connectToPeer(const QString &address, const QString &name)
void createServer(const QString &address, QDBusServer *server)
QDBusConnectionPrivate * connectToBus(QDBusConnection::BusType type, const QString &name, bool suspendedDelivery)
QDBusConnectionPrivate * existingConnection(const QString &name) const
void disconnectFrom(const QString &name, QDBusConnectionPrivate::ConnectionMode mode)
void setServer(QDBusServer *object, DBusServer *server, const QDBusErrorInternal &error)
\inmodule QtDBus
BusType
Specifies the type of the bus connection.
\inmodule QtDBus
Definition qdbusserver.h:21
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it.
Definition qhash.h:985
T value(const Key &key) const noexcept
Definition qhash.h:1054
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:951
void deleteLater()
\threadsafe
Definition qobject.cpp:2435
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QThread * currentThread()
Definition qthread.cpp:1039
@ DBUS_BUS_SESSION
@ DBUS_BUS_STARTER
@ DBUS_BUS_SYSTEM
Q_DBUS_EXPORT void init()
Combined button and popup list for selecting options.
Lock qt_scoped_lock(Mutex &mutex)
Definition qlocking_p.h:58
@ BlockingQueuedConnection
#define qApp
bool qdbus_loadLibDBus()
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall DBusPendingCall return DBusPendingCall return dbus_int32_t return DBusServer * server
DBusConnection const char DBusError * error
DBusConnection * connection
Q_DBUS_EXPORT void qDBusBindToApplication()
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
void qReturnArg(const T &&)=delete
GLenum mode
GLenum type
GLuint start
GLuint name
const GLubyte * c
GLuint GLuint * names
GLuint GLuint64EXT address
GLuint64EXT * result
[6]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
HINSTANCE HMODULE
myObject moveToThread(QApplication::instance() ->thread())
[6]
dialog exec()
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...