summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIevgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io>2023-08-15 12:49:23 +0200
committerIevgenii Meshcheriakov <ievgenii.meshcheriakov@qt.io>2023-08-21 12:18:33 +0200
commit338de683950b3826edfc29c5d64da1df6b21a360 (patch)
treecd6fc027d4049dfec8ad274e190ef17627eae40b
parent7a0de7fda2e8dc3910313b1ddc5befefd4995d31 (diff)
QDBusConnectionManager: Move to a separate source file
Split the source code into a separate file for easier code navigation and to better match the rest of Qt. Update the link to the blog post explaining the preventDllUnload() function, mention the blog post title to make it easier to find it again when the link breaks. Change-Id: I061d72bc795110f03352abf10fc639ddd6243527 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r--src/dbus/CMakeLists.txt2
-rw-r--r--src/dbus/qdbusconnection.cpp313
-rw-r--r--src/dbus/qdbusconnectionmanager.cpp265
3 files changed, 308 insertions, 272 deletions
diff --git a/src/dbus/CMakeLists.txt b/src/dbus/CMakeLists.txt
index 1ce8becb54..1c69fa51b2 100644
--- a/src/dbus/CMakeLists.txt
+++ b/src/dbus/CMakeLists.txt
@@ -15,7 +15,7 @@ qt_internal_add_module(DBus
qdbusargument.cpp qdbusargument.h qdbusargument_p.h
qdbusconnection.cpp qdbusconnection.h qdbusconnection_p.h
qdbusconnectioninterface.cpp qdbusconnectioninterface.h
- qdbusconnectionmanager_p.h
+ qdbusconnectionmanager.cpp qdbusconnectionmanager_p.h
qdbuscontext.cpp qdbuscontext.h qdbuscontext_p.h
qdbuserror.cpp qdbuserror.h
qdbusextratypes.cpp qdbusextratypes.h
diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp
index baab2b8ca5..f0e38dcbd4 100644
--- a/src/dbus/qdbusconnection.cpp
+++ b/src/dbus/qdbusconnection.cpp
@@ -6,23 +6,16 @@
#include "qdbusconnection_p.h"
#include <qdebug.h>
-#include <qcoreapplication.h>
#include <qstringlist.h>
-#include <qtimer.h>
-#include <qthread.h>
#include <QtCore/private/qlocking_p.h>
#include "qdbusconnectioninterface.h"
#include "qdbuserror.h"
#include "qdbusmessage.h"
-#include "qdbusmessage_p.h"
-#include "qdbusinterface_p.h"
#include "qdbusutil_p.h"
#include "qdbusconnectionmanager_p.h"
#include "qdbuspendingcall_p.h"
-
#include "qdbusthreaddebug_p.h"
-#include "qdbusmetatype_p.h"
#include <algorithm>
@@ -34,221 +27,6 @@
QT_BEGIN_NAMESPACE
-#ifdef Q_OS_WIN
-static void preventDllUnload();
-#endif
-
-Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager)
-
-QDBusConnectionPrivate *QDBusConnectionManager::busConnection(QDBusConnection::BusType type)
-{
- static_assert(int(QDBusConnection::SessionBus) + int(QDBusConnection::SystemBus) == 1);
- Q_ASSERT(type == QDBusConnection::SessionBus || type == QDBusConnection::SystemBus);
-
- if (!qdbus_loadLibDBus())
- return nullptr;
-
- // we'll start in suspended delivery mode if we're in the main thread
- // (the event loop will resume delivery)
- bool suspendedDelivery = qApp && qApp->thread() == QThread::currentThread();
-
- const auto locker = qt_scoped_lock(defaultBusMutex);
- if (defaultBuses[type])
- return defaultBuses[type];
-
- QString name = QStringLiteral("qt_default_session_bus");
- if (type == QDBusConnection::SystemBus)
- name = QStringLiteral("qt_default_system_bus");
- return defaultBuses[type] = connectToBus(type, name, suspendedDelivery);
-}
-
-QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
-{
- return connectionHash.value(name, nullptr);
-}
-
-void QDBusConnectionManager::removeConnection(const QString &name)
-{
- QDBusConnectionPrivate *d = nullptr;
- d = connectionHash.take(name);
- if (d && !d->ref.deref())
- d->deleteLater();
-
- // Static objects may be keeping the connection open.
- // However, it is harmless to have outstanding references to a connection that is
- // closing as long as those references will be soon dropped without being used.
-
- // ### Output a warning if connections are being used after they have been removed.
-}
-
-QDBusConnectionManager::QDBusConnectionManager()
-{
- // Ensure that the custom metatype registry is created before the instance
- // of this class. This will ensure that the registry is not destroyed before
- // the connection manager at application exit (see also QTBUG-58732). This
- // works with compilers that use mechanism similar to atexit() to call
- // destructurs for global statics.
- QDBusMetaTypeId::init();
-
- connect(this, &QDBusConnectionManager::connectionRequested,
- this, &QDBusConnectionManager::executeConnectionRequest, Qt::BlockingQueuedConnection);
- connect(this, &QDBusConnectionManager::serverRequested,
- this, &QDBusConnectionManager::createServer, Qt::BlockingQueuedConnection);
- moveToThread(this); // ugly, don't do this in other projects
-
-#ifdef Q_OS_WIN
- // prevent the library from being unloaded on Windows. See comments in the function.
- preventDllUnload();
-#endif
- defaultBuses[0] = defaultBuses[1] = nullptr;
- start();
-}
-
-QDBusConnectionManager::~QDBusConnectionManager()
-{
- quit();
- wait();
-}
-
-QDBusConnectionManager* QDBusConnectionManager::instance()
-{
- return _q_manager();
-}
-
-Q_DBUS_EXPORT void qDBusBindToApplication();
-void qDBusBindToApplication()
-{
-}
-
-void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
-{
- connectionHash[name] = c;
- c->name = name;
-}
-
-void QDBusConnectionManager::run()
-{
- exec();
-
- // cleanup:
- const auto locker = qt_scoped_lock(mutex);
- for (QDBusConnectionPrivate *d : std::as_const(connectionHash)) {
- if (!d->ref.deref()) {
- delete d;
- } else {
- d->closeConnection();
- d->moveToThread(nullptr); // allow it to be deleted in another thread
- }
- }
- connectionHash.clear();
-
- // allow deletion from any thread without warning
- moveToThread(nullptr);
-}
-
-QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(QDBusConnection::BusType type, const QString &name,
- bool suspendedDelivery)
-{
- ConnectionRequestData data;
- data.type = ConnectionRequestData::ConnectToStandardBus;
- data.busType = type;
- data.name = &name;
- data.suspendedDelivery = suspendedDelivery;
-
- emit connectionRequested(&data);
- if (suspendedDelivery && data.result->connection)
- data.result->enableDispatchDelayed(qApp); // qApp was checked in the caller
-
- return data.result;
-}
-
-QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(const QString &address, const QString &name)
-{
- ConnectionRequestData data;
- data.type = ConnectionRequestData::ConnectToBusByAddress;
- data.busAddress = &address;
- data.name = &name;
- data.suspendedDelivery = false;
-
- emit connectionRequested(&data);
- return data.result;
-}
-
-QDBusConnectionPrivate *QDBusConnectionManager::connectToPeer(const QString &address, const QString &name)
-{
- ConnectionRequestData data;
- data.type = ConnectionRequestData::ConnectToPeerByAddress;
- data.busAddress = &address;
- data.name = &name;
- data.suspendedDelivery = false;
-
- emit connectionRequested(&data);
- return data.result;
-}
-
-void QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData *data)
-{
- const auto locker = qt_scoped_lock(mutex);
- const QString &name = *data->name;
- QDBusConnectionPrivate *&d = data->result;
-
- // check if the connection exists by name
- d = connection(name);
- if (d || name.isEmpty())
- return;
-
- d = new QDBusConnectionPrivate;
- DBusConnection *c = nullptr;
- QDBusErrorInternal error;
- switch (data->type) {
- case ConnectionRequestData::ConnectToStandardBus:
- switch (data->busType) {
- case QDBusConnection::SystemBus:
- c = q_dbus_bus_get_private(DBUS_BUS_SYSTEM, error);
- break;
- case QDBusConnection::SessionBus:
- c = q_dbus_bus_get_private(DBUS_BUS_SESSION, error);
- break;
- case QDBusConnection::ActivationBus:
- c = q_dbus_bus_get_private(DBUS_BUS_STARTER, error);
- break;
- }
- break;
-
- case ConnectionRequestData::ConnectToBusByAddress:
- case ConnectionRequestData::ConnectToPeerByAddress:
- c = q_dbus_connection_open_private(data->busAddress->toUtf8().constData(), error);
- if (c && data->type == ConnectionRequestData::ConnectToBusByAddress) {
- // register on the bus
- if (!q_dbus_bus_register(c, error)) {
- q_dbus_connection_unref(c);
- c = nullptr;
- }
- }
- break;
- }
-
- setConnection(name, d);
- if (data->type == ConnectionRequestData::ConnectToPeerByAddress) {
- d->setPeer(c, error);
- } else {
- // create the bus service
- // will lock in QDBusConnectionPrivate::connectRelay()
- d->setConnection(c, error);
- d->createBusService();
- if (c && data->suspendedDelivery)
- d->setDispatchEnabled(false);
- }
-}
-
-void QDBusConnectionManager::createServer(const QString &address, void *server)
-{
- QDBusErrorInternal error;
- QDBusConnectionPrivate *d = new QDBusConnectionPrivate;
- d->setServer(static_cast<QDBusServer *>(server),
- q_dbus_server_listen(address.toUtf8().constData(), error), error);
-}
-
/*!
\class QDBusConnection
\inmodule QtDBus
@@ -373,11 +151,18 @@ void QDBusConnectionManager::createServer(const QString &address, void *server)
*/
QDBusConnection::QDBusConnection(const QString &name)
{
- if (name.isEmpty() || _q_manager.isDestroyed()) {
+ if (name.isEmpty()) {
+ d = nullptr;
+ return;
+ }
+
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager) {
d = nullptr;
} else {
- const auto locker = qt_scoped_lock(_q_manager()->mutex);
- d = _q_manager()->connection(name);
+ const auto locker = qt_scoped_lock(manager->mutex);
+ d = manager->connection(name);
if (d)
d->ref.ref();
}
@@ -438,11 +223,13 @@ QDBusConnection &QDBusConnection::operator=(const QDBusConnection &other)
*/
QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name)
{
- if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager || !qdbus_loadLibDBus()) {
QDBusConnectionPrivate *d = nullptr;
return QDBusConnection(d);
}
- return QDBusConnection(_q_manager()->connectToBus(type, name, false));
+ return QDBusConnection(manager->connectToBus(type, name, false));
}
/*!
@@ -452,11 +239,13 @@ QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name)
QDBusConnection QDBusConnection::connectToBus(const QString &address,
const QString &name)
{
- if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager || !qdbus_loadLibDBus()) {
QDBusConnectionPrivate *d = nullptr;
return QDBusConnection(d);
}
- return QDBusConnection(_q_manager()->connectToBus(address, name));
+ return QDBusConnection(manager->connectToBus(address, name));
}
/*!
\since 4.8
@@ -467,11 +256,13 @@ QDBusConnection QDBusConnection::connectToBus(const QString &address,
QDBusConnection QDBusConnection::connectToPeer(const QString &address,
const QString &name)
{
- if (_q_manager.isDestroyed() || !qdbus_loadLibDBus()) {
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager || !qdbus_loadLibDBus()) {
QDBusConnectionPrivate *d = nullptr;
return QDBusConnection(d);
}
- return QDBusConnection(_q_manager()->connectToPeer(address, name));
+ return QDBusConnection(manager->connectToPeer(address, name));
}
/*!
@@ -484,12 +275,14 @@ QDBusConnection QDBusConnection::connectToPeer(const QString &address,
*/
void QDBusConnection::disconnectFromBus(const QString &name)
{
- if (_q_manager()) {
- const auto locker = qt_scoped_lock(_q_manager()->mutex);
- QDBusConnectionPrivate *d = _q_manager()->connection(name);
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (manager) {
+ const auto locker = qt_scoped_lock(manager->mutex);
+ QDBusConnectionPrivate *d = manager->connection(name);
if (d && d->mode != QDBusConnectionPrivate::ClientMode)
return;
- _q_manager()->removeConnection(name);
+ manager->removeConnection(name);
}
}
@@ -505,12 +298,14 @@ void QDBusConnection::disconnectFromBus(const QString &name)
*/
void QDBusConnection::disconnectFromPeer(const QString &name)
{
- if (_q_manager()) {
- const auto locker = qt_scoped_lock(_q_manager()->mutex);
- QDBusConnectionPrivate *d = _q_manager()->connection(name);
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (manager) {
+ const auto locker = qt_scoped_lock(manager->mutex);
+ QDBusConnectionPrivate *d = manager->connection(name);
if (d && d->mode != QDBusConnectionPrivate::PeerMode)
return;
- _q_manager()->removeConnection(name);
+ manager->removeConnection(name);
}
}
@@ -1131,9 +926,11 @@ bool QDBusConnection::unregisterService(const QString &serviceName)
*/
QDBusConnection QDBusConnection::sessionBus()
{
- if (_q_manager.isDestroyed())
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager)
return QDBusConnection(nullptr);
- return QDBusConnection(_q_manager()->busConnection(SessionBus));
+ return QDBusConnection(manager->busConnection(SessionBus));
}
/*!
@@ -1145,9 +942,11 @@ QDBusConnection QDBusConnection::sessionBus()
*/
QDBusConnection QDBusConnection::systemBus()
{
- if (_q_manager.isDestroyed())
+ auto *manager = QDBusConnectionManager::instance();
+
+ if (!manager)
return QDBusConnection(nullptr);
- return QDBusConnection(_q_manager()->busConnection(SystemBus));
+ return QDBusConnection(manager->busConnection(SystemBus));
}
/*!
@@ -1224,33 +1023,5 @@ QT_END_NAMESPACE
#include "moc_qdbusconnection_p.cpp"
#include "moc_qdbusconnection.cpp"
-#include "moc_qdbusconnectionmanager_p.cpp"
-
-#ifdef Q_OS_WIN
-# include <qt_windows.h>
-
-QT_BEGIN_NAMESPACE
-static void preventDllUnload()
-{
- // Thread termination is really wacky on Windows. For some reason we don't
- // understand, exiting from the thread may try to unload the DLL. Since the
- // QDBusConnectionManager thread runs until the DLL is unloaded, we've got
- // a deadlock: the main thread is waiting for the manager thread to exit,
- // but the manager thread is attempting to acquire a lock to unload the DLL.
- //
- // We work around the issue by preventing the unload from happening in the
- // first place.
- //
- // For this trick, see
- // https://blogs.msdn.microsoft.com/oldnewthing/20131105-00/?p=2733
-
- static HMODULE self;
- GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
- GET_MODULE_HANDLE_EX_FLAG_PIN,
- reinterpret_cast<const wchar_t *>(&self), // any address in this DLL
- &self);
-}
-QT_END_NAMESPACE
-#endif
#endif // QT_NO_DBUS
diff --git a/src/dbus/qdbusconnectionmanager.cpp b/src/dbus/qdbusconnectionmanager.cpp
new file mode 100644
index 0000000000..96d8d32185
--- /dev/null
+++ b/src/dbus/qdbusconnectionmanager.cpp
@@ -0,0 +1,265 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2016 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qdbusconnectionmanager_p.h"
+
+#include <qcoreapplication.h>
+#include <qthread.h>
+#include <QtCore/private/qlocking_p.h>
+
+#include "qdbuserror.h"
+#include "qdbuspendingcall_p.h"
+#include "qdbusmetatype_p.h"
+
+#ifndef QT_NO_DBUS
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_OS_WIN
+static void preventDllUnload();
+#endif
+
+Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager)
+
+QDBusConnectionPrivate *QDBusConnectionManager::busConnection(QDBusConnection::BusType type)
+{
+ static_assert(int(QDBusConnection::SessionBus) + int(QDBusConnection::SystemBus) == 1);
+ Q_ASSERT(type == QDBusConnection::SessionBus || type == QDBusConnection::SystemBus);
+
+ if (!qdbus_loadLibDBus())
+ return nullptr;
+
+ // we'll start in suspended delivery mode if we're in the main thread
+ // (the event loop will resume delivery)
+ bool suspendedDelivery = qApp && qApp->thread() == QThread::currentThread();
+
+ const auto locker = qt_scoped_lock(defaultBusMutex);
+ if (defaultBuses[type])
+ return defaultBuses[type];
+
+ QString name = QStringLiteral("qt_default_session_bus");
+ if (type == QDBusConnection::SystemBus)
+ name = QStringLiteral("qt_default_system_bus");
+ return defaultBuses[type] = connectToBus(type, name, suspendedDelivery);
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::connection(const QString &name) const
+{
+ return connectionHash.value(name, nullptr);
+}
+
+void QDBusConnectionManager::removeConnection(const QString &name)
+{
+ QDBusConnectionPrivate *d = nullptr;
+ d = connectionHash.take(name);
+ if (d && !d->ref.deref())
+ d->deleteLater();
+
+ // Static objects may be keeping the connection open.
+ // However, it is harmless to have outstanding references to a connection that is
+ // closing as long as those references will be soon dropped without being used.
+
+ // ### Output a warning if connections are being used after they have been removed.
+}
+
+QDBusConnectionManager::QDBusConnectionManager()
+{
+ // Ensure that the custom metatype registry is created before the instance
+ // of this class. This will ensure that the registry is not destroyed before
+ // the connection manager at application exit (see also QTBUG-58732). This
+ // works with compilers that use mechanism similar to atexit() to call
+ // destructurs for global statics.
+ QDBusMetaTypeId::init();
+
+ connect(this, &QDBusConnectionManager::connectionRequested,
+ this, &QDBusConnectionManager::executeConnectionRequest, Qt::BlockingQueuedConnection);
+ connect(this, &QDBusConnectionManager::serverRequested,
+ this, &QDBusConnectionManager::createServer, Qt::BlockingQueuedConnection);
+ moveToThread(this); // ugly, don't do this in other projects
+
+#ifdef Q_OS_WIN
+ // prevent the library from being unloaded on Windows. See comments in the function.
+ preventDllUnload();
+#endif
+ defaultBuses[0] = defaultBuses[1] = nullptr;
+ start();
+}
+
+QDBusConnectionManager::~QDBusConnectionManager()
+{
+ quit();
+ wait();
+}
+
+QDBusConnectionManager* QDBusConnectionManager::instance()
+{
+ return _q_manager();
+}
+
+Q_DBUS_EXPORT void qDBusBindToApplication();
+void qDBusBindToApplication()
+{
+}
+
+void QDBusConnectionManager::setConnection(const QString &name, QDBusConnectionPrivate *c)
+{
+ connectionHash[name] = c;
+ c->name = name;
+}
+
+void QDBusConnectionManager::run()
+{
+ exec();
+
+ // cleanup:
+ const auto locker = qt_scoped_lock(mutex);
+ for (QDBusConnectionPrivate *d : std::as_const(connectionHash)) {
+ if (!d->ref.deref()) {
+ delete d;
+ } else {
+ d->closeConnection();
+ d->moveToThread(nullptr); // allow it to be deleted in another thread
+ }
+ }
+ connectionHash.clear();
+
+ // allow deletion from any thread without warning
+ moveToThread(nullptr);
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(QDBusConnection::BusType type, const QString &name,
+ bool suspendedDelivery)
+{
+ ConnectionRequestData data;
+ data.type = ConnectionRequestData::ConnectToStandardBus;
+ data.busType = type;
+ data.name = &name;
+ data.suspendedDelivery = suspendedDelivery;
+
+ emit connectionRequested(&data);
+ if (suspendedDelivery && data.result->connection)
+ data.result->enableDispatchDelayed(qApp); // qApp was checked in the caller
+
+ return data.result;
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::connectToBus(const QString &address, const QString &name)
+{
+ ConnectionRequestData data;
+ data.type = ConnectionRequestData::ConnectToBusByAddress;
+ data.busAddress = &address;
+ data.name = &name;
+ data.suspendedDelivery = false;
+
+ emit connectionRequested(&data);
+ return data.result;
+}
+
+QDBusConnectionPrivate *QDBusConnectionManager::connectToPeer(const QString &address, const QString &name)
+{
+ ConnectionRequestData data;
+ data.type = ConnectionRequestData::ConnectToPeerByAddress;
+ data.busAddress = &address;
+ data.name = &name;
+ data.suspendedDelivery = false;
+
+ emit connectionRequested(&data);
+ return data.result;
+}
+
+void QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData *data)
+{
+ const auto locker = qt_scoped_lock(mutex);
+ const QString &name = *data->name;
+ QDBusConnectionPrivate *&d = data->result;
+
+ // check if the connection exists by name
+ d = connection(name);
+ if (d || name.isEmpty())
+ return;
+
+ d = new QDBusConnectionPrivate;
+ DBusConnection *c = nullptr;
+ QDBusErrorInternal error;
+ switch (data->type) {
+ case ConnectionRequestData::ConnectToStandardBus:
+ switch (data->busType) {
+ case QDBusConnection::SystemBus:
+ c = q_dbus_bus_get_private(DBUS_BUS_SYSTEM, error);
+ break;
+ case QDBusConnection::SessionBus:
+ c = q_dbus_bus_get_private(DBUS_BUS_SESSION, error);
+ break;
+ case QDBusConnection::ActivationBus:
+ c = q_dbus_bus_get_private(DBUS_BUS_STARTER, error);
+ break;
+ }
+ break;
+
+ case ConnectionRequestData::ConnectToBusByAddress:
+ case ConnectionRequestData::ConnectToPeerByAddress:
+ c = q_dbus_connection_open_private(data->busAddress->toUtf8().constData(), error);
+ if (c && data->type == ConnectionRequestData::ConnectToBusByAddress) {
+ // register on the bus
+ if (!q_dbus_bus_register(c, error)) {
+ q_dbus_connection_unref(c);
+ c = nullptr;
+ }
+ }
+ break;
+ }
+
+ setConnection(name, d);
+ if (data->type == ConnectionRequestData::ConnectToPeerByAddress) {
+ d->setPeer(c, error);
+ } else {
+ // create the bus service
+ // will lock in QDBusConnectionPrivate::connectRelay()
+ d->setConnection(c, error);
+ d->createBusService();
+ if (c && data->suspendedDelivery)
+ d->setDispatchEnabled(false);
+ }
+}
+
+void QDBusConnectionManager::createServer(const QString &address, void *server)
+{
+ QDBusErrorInternal error;
+ QDBusConnectionPrivate *d = new QDBusConnectionPrivate;
+ d->setServer(static_cast<QDBusServer *>(server),
+ q_dbus_server_listen(address.toUtf8().constData(), error), error);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qdbusconnectionmanager_p.cpp"
+
+#ifdef Q_OS_WIN
+# include <qt_windows.h>
+
+QT_BEGIN_NAMESPACE
+static void preventDllUnload()
+{
+ // Thread termination is really wacky on Windows. For some reason we don't
+ // understand, exiting from the thread may try to unload the DLL. Since the
+ // QDBusConnectionManager thread runs until the DLL is unloaded, we've got
+ // a deadlock: the main thread is waiting for the manager thread to exit,
+ // but the manager thread is attempting to acquire a lock to unload the DLL.
+ //
+ // We work around the issue by preventing the unload from happening in the
+ // first place.
+ //
+ // For this trick, see the blog post titled "What is the point of FreeLibraryAndExitThread?"
+ // https://devblogs.microsoft.com/oldnewthing/20131105-00/?p=2733
+
+ static HMODULE self;
+ GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+ GET_MODULE_HANDLE_EX_FLAG_PIN,
+ reinterpret_cast<const wchar_t *>(&self), // any address in this DLL
+ &self);
+}
+QT_END_NAMESPACE
+#endif
+
+#endif // QT_NO_DBUS