diff options
Diffstat (limited to 'src/dbus/qdbusconnection.cpp')
-rw-r--r-- | src/dbus/qdbusconnection.cpp | 314 |
1 files changed, 42 insertions, 272 deletions
diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index 9ce13e769c..f6918b70b0 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -6,21 +6,14 @@ #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 <algorithm> @@ -33,214 +26,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() -{ - 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 @@ -365,13 +150,17 @@ 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); - if (d) - d->ref.ref(); + d = manager->existingConnection(name); } } @@ -430,11 +219,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)); } /*! @@ -444,11 +235,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 @@ -459,11 +252,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)); } /*! @@ -476,13 +271,11 @@ 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); - if (d && d->mode != QDBusConnectionPrivate::ClientMode) - return; - _q_manager()->removeConnection(name); - } + auto *manager = QDBusConnectionManager::instance(); + if (!manager) + return; + + manager->disconnectFrom(name, QDBusConnectionPrivate::ClientMode); } /*! @@ -497,13 +290,11 @@ 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); - if (d && d->mode != QDBusConnectionPrivate::PeerMode) - return; - _q_manager()->removeConnection(name); - } + auto *manager = QDBusConnectionManager::instance(); + if (!manager) + return; + + manager->disconnectFrom(name, QDBusConnectionPrivate::PeerMode); } /*! @@ -640,6 +431,9 @@ QDBusMessage QDBusConnection::call(const QDBusMessage &message, QDBus::CallMode See the QDBusInterface::asyncCall() function for a more friendly way of placing calls. + + \note Method calls to objects registered by the application itself are never + asynchronous due to implementation limitations. */ QDBusPendingCall QDBusConnection::asyncCall(const QDBusMessage &message, int timeout) const { @@ -1123,9 +917,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)); } /*! @@ -1137,9 +933,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)); } /*! @@ -1216,33 +1014,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 |