summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMÃ¥rten Nordheim <marten.nordheim@qt.io>2021-04-13 17:01:38 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-04-14 17:56:22 +0000
commit6a4b3e861e1e191657181a74eeb4e60a52d12ca3 (patch)
treec96b469b041f8837f2d63a9ff87aa59e350a8f81
parent029a79e7c0ad7ec5f3d3aa7f51417e6585f67e29 (diff)
QNetworkInformation: delete the instance as a post-routine
On Windows, on exit, the backend will deref (and then implicitly start deletion of) a COM object. This object tries to communicate with an object in another thread, though it seems this other thread quits before the main thread in _most_ cases. To get around this we move the deletion to earlier in the program. While this is only reported as a Windows issue it makes for more consistent behavior if all platforms behave the same. Document and test that recreation of QNI works as expected after the destruction (and recreation) of QCoreApplication. Amends: 0875626e22ad4e709ddf505e701a8d699559f5b4 Fixes: QTBUG-92568 Change-Id: Iffc07f38673019aa059efd4d64d2ad706a03f6fe Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Oliver Wolff <oliver.wolff@qt.io> (cherry picked from commit e875c071ec32ab9aa460c982f25f6c6191e41326) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/network/kernel/qnetworkinformation.cpp26
-rw-r--r--tests/auto/network/kernel/CMakeLists.txt1
-rw-r--r--tests/auto/network/kernel/qnetworkinformation_appless/CMakeLists.txt6
-rw-r--r--tests/auto/network/kernel/qnetworkinformation_appless/tst_qnetworkinformation_appless.cpp67
4 files changed, 98 insertions, 2 deletions
diff --git a/src/network/kernel/qnetworkinformation.cpp b/src/network/kernel/qnetworkinformation.cpp
index 355c6ab411..7e19c02924 100644
--- a/src/network/kernel/qnetworkinformation.cpp
+++ b/src/network/kernel/qnetworkinformation.cpp
@@ -46,6 +46,7 @@
#include <QtCore/private/qobject_p.h>
#include <QtCore/qcoreapplication.h>
#include <QtCore/qmutex.h>
+#include <QtCore/qthread.h>
#include <QtCore/private/qfactoryloader_p.h>
#include <algorithm>
@@ -73,11 +74,30 @@ struct QStaticNetworkInformationDataHolder
};
Q_GLOBAL_STATIC(QStaticNetworkInformationDataHolder, dataHolder);
+static void networkInfoCleanup()
+{
+ if (!dataHolder.exists())
+ return;
+ QMutexLocker locker(&dataHolder->instanceMutex);
+ QNetworkInformation *instance = dataHolder->instanceHolder.get();
+ if (!instance)
+ return;
+
+ auto needsReinvoke = instance->thread() && instance->thread() != QThread::currentThread();
+ if (needsReinvoke) {
+ QMetaObject::invokeMethod(dataHolder->instanceHolder.get(), []() { networkInfoCleanup(); });
+ return;
+ }
+ dataHolder->instanceHolder.reset();
+}
+
class QNetworkInformationPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QNetworkInformation)
public:
- QNetworkInformationPrivate(QNetworkInformationBackend *backend) : backend(backend) { }
+ QNetworkInformationPrivate(QNetworkInformationBackend *backend) : backend(backend) {
+ qAddPostRoutine(&networkInfoCleanup);
+ }
static QNetworkInformation *create(QNetworkInformation::Features features);
static QNetworkInformation *create(QStringView name);
@@ -408,7 +428,9 @@ QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory()
you can load() plugins based on which features are needed.
QNetworkInformation is a singleton and stays alive from the first
- successful load() until application shutdown.
+ successful load() until destruction of the QCoreApplication object.
+ If you destroy and re-create the QCoreApplication object you must call
+ load() again.
\sa QNetworkInformation::Feature
*/
diff --git a/tests/auto/network/kernel/CMakeLists.txt b/tests/auto/network/kernel/CMakeLists.txt
index 89526fa14c..11b859011e 100644
--- a/tests/auto/network/kernel/CMakeLists.txt
+++ b/tests/auto/network/kernel/CMakeLists.txt
@@ -14,4 +14,5 @@ endif()
if(QT_FEATURE_private_tests)
add_subdirectory(qauthenticator)
add_subdirectory(qnetworkinformation)
+ add_subdirectory(qnetworkinformation_appless)
endif()
diff --git a/tests/auto/network/kernel/qnetworkinformation_appless/CMakeLists.txt b/tests/auto/network/kernel/qnetworkinformation_appless/CMakeLists.txt
new file mode 100644
index 0000000000..76cbf594c3
--- /dev/null
+++ b/tests/auto/network/kernel/qnetworkinformation_appless/CMakeLists.txt
@@ -0,0 +1,6 @@
+qt_internal_add_test(tst_qnetworkinformation_appless
+ SOURCES
+ tst_qnetworkinformation_appless.cpp
+ PUBLIC_LIBRARIES
+ Qt::Network
+)
diff --git a/tests/auto/network/kernel/qnetworkinformation_appless/tst_qnetworkinformation_appless.cpp b/tests/auto/network/kernel/qnetworkinformation_appless/tst_qnetworkinformation_appless.cpp
new file mode 100644
index 0000000000..ff058e8a9b
--- /dev/null
+++ b/tests/auto/network/kernel/qnetworkinformation_appless/tst_qnetworkinformation_appless.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qcoreapplication.h>
+#include <QtNetwork/qnetworkinformation.h>
+#include <QtTest/qtest.h>
+
+class tst_QNetworkInformation_appless : public QObject
+{
+ Q_OBJECT
+private slots:
+ void reinit();
+};
+
+void tst_QNetworkInformation_appless::reinit()
+{
+ int argc = 1;
+ char name[] = "./test";
+ char *argv[] = { name, nullptr };
+
+ {
+ QCoreApplication app(argc, argv);
+ if (QNetworkInformation::availableBackends().isEmpty())
+ QSKIP("No backends available!");
+
+ QVERIFY(QNetworkInformation::load(QNetworkInformation::Feature::Reachability));
+ auto info = QNetworkInformation::instance();
+ QVERIFY(info);
+ }
+
+ QVERIFY(!QNetworkInformation::instance());
+
+ {
+ QCoreApplication app(argc, argv);
+ QVERIFY(QNetworkInformation::load(QNetworkInformation::Feature::Reachability));
+ auto info = QNetworkInformation::instance();
+ QVERIFY(info);
+ }
+}
+
+QTEST_APPLESS_MAIN(tst_QNetworkInformation_appless);
+#include "tst_qnetworkinformation_appless.moc"