diff options
author | Thiago Macieira <[email protected]> | 2025-07-02 09:20:25 -0700 |
---|---|---|
committer | Thiago Macieira <[email protected]> | 2025-07-14 17:53:34 -0700 |
commit | 7ea2bbe25745ef8130fe6dddb0c3acb78f72571e (patch) | |
tree | c0c210e68b6fff6e6b1295e5a3586c1f7527a481 | |
parent | 76d95f4c024ee13784e44d0a2d0e4c455863564f (diff) |
QDBusConnection: don't disable delivery if !qApp
Amends commit 6fb39ca2cbb111469ce09c8342997eb5375e3239, which removed
the qApp check because the comment above the check didn't say it was
needed. In fact, that made the code match the comment. But if qApp is
null, we'd post an event to nullptr to reenable delivery, which meant it
was never re-enabled, resulting in stalled applications. The sequence
implied it was necessary:
if (suspendedDelivery && result && result->connection)
result->enableDispatchDelayed(qApp); // qApp was checked in the caller
Ideally we would make the comment true and re-enable without requiring a
QCoreApplication object, but qAddPreRoutine() takes a parameter-less
function and I'm not going to spend time adding more complexity to that.
Instead, let's just restore behavior.
Pick-to: 6.10 6.9 6.8
Fixes: QTBUG-135928
Change-Id: I40c54d1343e7d0c0f5f3fffdd05e84d01d5df025
Reviewed-by: Ivan Solovev <[email protected]>
Reviewed-by: MÃ¥rten Nordheim <[email protected]>
Reviewed-by: Fabian Kosmale <[email protected]>
5 files changed, 97 insertions, 2 deletions
diff --git a/src/dbus/qdbusconnectionmanager.cpp b/src/dbus/qdbusconnectionmanager.cpp index 73f11d82280..d41178b5c30 100644 --- a/src/dbus/qdbusconnectionmanager.cpp +++ b/src/dbus/qdbusconnectionmanager.cpp @@ -32,8 +32,8 @@ QDBusConnectionPrivate *QDBusConnectionManager::busConnection(QDBusConnection::B return nullptr; // we'll start in suspended delivery mode if we're in the main thread - // (the event loop will resume delivery) - bool suspendedDelivery = QThread::isMainThread(); + // (the event loop will resume delivery) and QCoreApplication already exists + bool suspendedDelivery = QThread::isMainThread() && qApp; const auto locker = qt_scoped_lock(defaultBusMutex); if (defaultBuses[type]) diff --git a/tests/auto/dbus/qdbusconnection/CMakeLists.txt b/tests/auto/dbus/qdbusconnection/CMakeLists.txt index 56ae21f2911..cbbe76a7dc7 100644 --- a/tests/auto/dbus/qdbusconnection/CMakeLists.txt +++ b/tests/auto/dbus/qdbusconnection/CMakeLists.txt @@ -19,3 +19,15 @@ qt_internal_add_test(tst_qdbusconnection TESTDATA tst_qdbusconnection.conf ) + +qt_internal_add_executable(qdbusdelayeddeliveryreenablehelper + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/" + SOURCES + qdbusdelayeddeliveryreenablehelper.cpp + LIBRARIES + Qt::DBus +) + +add_dependencies(tst_qdbusconnection + qdbusdelayeddeliveryreenablehelper +) diff --git a/tests/auto/dbus/qdbusconnection/qdbusdelayeddeliveryreenablehelper.cpp b/tests/auto/dbus/qdbusconnection/qdbusdelayeddeliveryreenablehelper.cpp new file mode 100644 index 00000000000..cd916d5b639 --- /dev/null +++ b/tests/auto/dbus/qdbusconnection/qdbusdelayeddeliveryreenablehelper.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2025 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QtCore/QTimer> +#include <QtCore/QCoreApplication> +#include <QtDBus/QDBusConnection> +#include <QtDBus/QDBusMessage> + +#include <stdio.h> + +using namespace Qt::StringLiterals; +using namespace std::chrono_literals; + +static QString myInterface() +{ + return u"local.qdbusdelayeddeliveryreenablehelper"_s; +} + +static void makeSynchronousCall(QDBusConnection &conn) +{ + QDBusMessage msg = QDBusMessage::createMethodCall("org.freedesktop.DBus", "/", + "org.freedesktop.DBus.Peer", "Ping"); + conn.call(msg); +} + +static void emitSignal(QDBusConnection &conn) +{ + QDBusMessage msg = QDBusMessage::createSignal("/", myInterface(), "quit"); + conn.send(msg); +} + +int main(int argc, char **argv) +{ + // Open a connection to the bus *before* QCoreApplication exists; + // this will put the connection in delayed delivery mode + QDBusConnection session = QDBusConnection::sessionBus(); + if (!session.isConnected()) { + fprintf(stderr, "Session bus did not connect!"); + return 1; + } + makeSynchronousCall(session); + + QCoreApplication app(argc, argv); + QTimer::singleShot(15s, qApp, [] { + fprintf(stderr, "Did not receive signal.\n"); + qApp->exit(1); + }); + + // connect a remote, wildcard signal to qApp->quit() + session.connect(QString(), QString(), myInterface(), "quit", &app, SLOT(quit())); + + // send ourselves the signal to quit, via D-Bus + emitSignal(session); + + return app.exec(); +} diff --git a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp index 5c07b6ad37b..fe9214c5513 100644 --- a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp +++ b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp @@ -1468,6 +1468,31 @@ void tst_QDBusConnection::parentClassSignal() QTRY_COMPARE(recv.signalsReceived, 2); } +// see also tst_qdbusconnection_delayed +void tst_QDBusConnection::delayedDeliveryReenabledAfterUsedInMainThread() +{ +#if !QT_CONFIG(process) + QSKIP("Test requires QProcess"); +#elif defined(HAS_HOOKSETUPFUNCTION) + QSKIP("No difference to run by tst_QDBusConnection"); +#else +# if defined(Q_OS_WIN) +# define EXE ".exe" +# else +# define EXE "" +# endif + if (!QCoreApplication::instance()) + QSKIP("Test requires a QCoreApplication"); + + QProcess process; + process.start(QFINDTESTDATA("qdbusdelayeddeliveryreenablehelper" EXE)); + QVERIFY2(process.waitForFinished(25000), qPrintable(process.errorString())); + QCOMPARE(process.readAllStandardError(), QString()); + QCOMPARE(process.exitCode(), 0); +# undef EXE +#endif +} + QString MyObject::path; QString MyObjectWithoutInterface::path; QString MyObjectWithoutInterface::interface; diff --git a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h index 4137859414c..dc37e3157b4 100644 --- a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h +++ b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.h @@ -126,6 +126,8 @@ private slots: void parentClassSignal(); + void delayedDeliveryReenabledAfterUsedInMainThread(); + public: QString serviceName() const { return "org.qtproject.Qt.Autotests.QDBusConnection"; } bool callMethod(const QDBusConnection &conn, const QString &path); |