From a6591cfe2ca96c36a63a12b5fd124c174e761fb5 Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Thu, 7 May 2015 20:19:06 +0200 Subject: [PATCH] refs #395, allow to disconnect SIGNAL/SLOTS from provider and gracefully shutdown airspace and analyzer --- src/blackcore/airspace_analyzer.cpp | 18 +++++++++------ src/blackcore/airspace_analyzer.h | 5 +++- src/blackcore/airspace_monitor.cpp | 23 +++++++++++++++++-- src/blackcore/airspace_monitor.h | 6 +++++ src/blackcore/context_network.h | 2 +- src/blackcore/context_network_empty.h | 2 +- src/blackcore/context_network_impl.cpp | 9 +++++++- src/blackcore/context_network_impl.h | 6 ++++- src/blackcore/context_network_proxy.cpp | 2 +- src/blackcore/context_network_proxy.h | 2 +- src/blackcore/context_simulator_impl.cpp | 19 +++++++-------- src/blackcore/simulator_common.cpp | 7 +++--- src/blackcore/simulator_common.h | 2 +- .../simulation/remoteaircraftprovider.h | 5 ++++ .../remoteaircraftproviderdummy.cpp | 6 +++++ .../simulation/remoteaircraftproviderdummy.h | 3 +++ 16 files changed, 87 insertions(+), 30 deletions(-) diff --git a/src/blackcore/airspace_analyzer.cpp b/src/blackcore/airspace_analyzer.cpp index 3815e4e56..d6ae9fe4e 100644 --- a/src/blackcore/airspace_analyzer.cpp +++ b/src/blackcore/airspace_analyzer.cpp @@ -29,10 +29,9 @@ namespace BlackCore this->setObjectName("CAirspaceAnalyzer"); // all in new thread from here on - m_timer = new QTimer(this); - m_timer->setObjectName(this->objectName().append(":m_timer")); - m_timer->start(5000); - bool c = connect(m_timer, &QTimer::timeout, this, &CAirspaceAnalyzer::ps_timeout); + m_timer.setObjectName(this->objectName().append(":m_timer")); + m_timer.start(5000); + bool c = connect(&m_timer, &QTimer::timeout, this, &CAirspaceAnalyzer::ps_timeout); Q_ASSERT(c); // disconnect @@ -72,6 +71,11 @@ namespace BlackCore this->m_simulatorMaxRenderedBoundary = maxRenderedBoundary; } + void CAirspaceAnalyzer::gracefulShutdown() + { + this->m_timer.stop(); + } + void CAirspaceAnalyzer::ps_watchdogTouchAircraftCallsign(const CAircraftSituation &situation, const CTransponder &transponder) { Q_ASSERT_X(!situation.getCallsign().isEmpty(), Q_FUNC_INFO, "No callsign in situaton"); @@ -93,11 +97,11 @@ namespace BlackCore if (newStatus == INetwork::Disconnected) { this->clear(); - this->m_timer->stop(); + this->m_timer.stop(); } else if (newStatus == INetwork::Connected) { - this->m_timer->start(); + this->m_timer.start(); } } @@ -129,7 +133,7 @@ namespace BlackCore qint64 currentTimeMsEpoch = QDateTime::currentMSecsSinceEpoch(); qint64 callDiffMs = currentTimeMsEpoch - m_lastWatchdogCallMsSinceEpoch; - qint64 callThresholdMs = m_timer->interval() * 1.5; + qint64 callThresholdMs = m_timer.interval() * 1.5; m_lastWatchdogCallMsSinceEpoch = currentTimeMsEpoch; // this is a trick to not remove everything while debugging diff --git a/src/blackcore/airspace_analyzer.h b/src/blackcore/airspace_analyzer.h index 1473e22f0..6e0aca3bf 100644 --- a/src/blackcore/airspace_analyzer.h +++ b/src/blackcore/airspace_analyzer.h @@ -55,6 +55,9 @@ namespace BlackCore //! Render restrictions in simulator void setSimulatorRenderRestrictionsChanged(bool restricted, int maxAircraft, const BlackMisc::PhysicalQuantities::CLength &maxRenderedDistance, const BlackMisc::PhysicalQuantities::CLength &maxRenderedBoundary); + //! Gracefully shut down, e.g. for thread safety + void gracefulShutdown(); + public slots: //! Clear void clear(); @@ -96,7 +99,7 @@ namespace BlackCore //! Analyze the airspace void analyzeAirspace(); - QTimer *m_timer = nullptr; //!< multi purpose timer for snapshots and watchdog + QTimer m_timer{this}; //!< multi purpose timer for snapshots and watchdog // watchdog CCallsignTimestampSet m_aircraftCallsignTimestamps; //!< for watchdog (pilots) diff --git a/src/blackcore/airspace_monitor.cpp b/src/blackcore/airspace_monitor.cpp index 3f22672ef..327302a68 100644 --- a/src/blackcore/airspace_monitor.cpp +++ b/src/blackcore/airspace_monitor.cpp @@ -148,6 +148,12 @@ namespace BlackCore return s1 && s2 && s3 && s4; } + bool CAirspaceMonitor::disconnectRemoteAircraftProviderSignals(QObject *receiver) + { + if (!receiver) { return false; } + return this->disconnect(receiver); + } + bool CAirspaceMonitor::updateAircraftEnabled(const CCallsign &callsign, bool enabledForRedering, const QString &originator) { Q_UNUSED(originator); @@ -404,11 +410,24 @@ namespace BlackCore void CAirspaceMonitor::enableFastPositionSending(bool enable) { - if (enable) m_interimPositionUpdateTimer.start(); - else m_interimPositionUpdateTimer.stop(); + if (enable) + { + m_interimPositionUpdateTimer.start(); + } + else + { + m_interimPositionUpdateTimer.stop(); + } m_sendInterimPositions = enable; } + void CAirspaceMonitor::gracefulShutdown() + { + if (this->m_analyzer) { this->m_analyzer->gracefulShutdown(); } + QObject::disconnect(this); + this->enableFastPositionSending(false); + } + bool CAirspaceMonitor::isFastPositionSendingEnabled() const { return m_sendInterimPositions; diff --git a/src/blackcore/airspace_monitor.h b/src/blackcore/airspace_monitor.h index 814ceb2bb..53594030f 100644 --- a/src/blackcore/airspace_monitor.h +++ b/src/blackcore/airspace_monitor.h @@ -154,6 +154,9 @@ namespace BlackCore std::function aircraftSnapshotSlot ) override; + //! \copydoc IRemoteAircraftProvider::disconnectRemoteAircraftProviderSignals + virtual bool disconnectRemoteAircraftProviderSignals(QObject *receiver) override; + //! Is interim position sending enabled? bool isFastPositionSendingEnabled() const; @@ -163,6 +166,9 @@ namespace BlackCore //! Analyzer CAirspaceAnalyzer *analyzer() const { return m_analyzer; } + //! Gracefully shut down, e.g. for thread safety + void gracefulShutdown(); + static const qint64 AircraftSituationsRemovedOffsetMs = 30 * 1000; //!< situations older than now - offset will be removed static const qint64 AircraftPartsRemoveOffsetMs = 30 * 1000; //!< parts older than now - offset will be removed diff --git a/src/blackcore/context_network.h b/src/blackcore/context_network.h index e2ce3c1d0..dc9f3ee66 100644 --- a/src/blackcore/context_network.h +++ b/src/blackcore/context_network.h @@ -196,7 +196,7 @@ namespace BlackCore //! Connect to Network //! \return messages generated during connecting //! \see INetwork::LoginMode - virtual BlackMisc::CStatusMessage connectToNetwork(const BlackMisc::Network::CServer &server, uint loginMode) = 0; + virtual BlackMisc::CStatusMessage connectToNetwork(const BlackMisc::Network::CServer &server, int loginMode) = 0; //! Server which is connected, if not connected empty default object. virtual BlackMisc::Network::CServer getConnectedServer() const = 0; diff --git a/src/blackcore/context_network_empty.h b/src/blackcore/context_network_empty.h index 0b56cb6ba..6d8ac92dc 100644 --- a/src/blackcore/context_network_empty.h +++ b/src/blackcore/context_network_empty.h @@ -82,7 +82,7 @@ namespace BlackCore } //! \copydoc IContextNetwork::connectToNetwork - virtual BlackMisc::CStatusMessage connectToNetwork(const BlackMisc::Network::CServer &server, uint mode) override + virtual BlackMisc::CStatusMessage connectToNetwork(const BlackMisc::Network::CServer &server, int mode) override { Q_UNUSED(mode); Q_UNUSED(server); diff --git a/src/blackcore/context_network_impl.cpp b/src/blackcore/context_network_impl.cpp index cf38214f8..9c1b0f26a 100644 --- a/src/blackcore/context_network_impl.cpp +++ b/src/blackcore/context_network_impl.cpp @@ -135,14 +135,21 @@ namespace BlackCore return this->m_airspace->connectRemoteAircraftProviderSignals(situationSlot, partsSlot, removedAircraftSlot, aircraftSnapshotSlot); } + bool CContextNetwork::disconnectRemoteAircraftProviderSignals(QObject *receiver) + { + Q_ASSERT(this->m_airspace); + return this->m_airspace->disconnectRemoteAircraftProviderSignals(receiver); + } + void CContextNetwork::gracefulShutdown() { if (this->m_vatsimBookingReader) { this->m_vatsimBookingReader->requestStop(); this->m_vatsimBookingReader->quit(); } if (this->m_vatsimDataFileReader) { this->m_vatsimDataFileReader->requestStop(); this->m_vatsimDataFileReader->quit(); } if (this->isConnected()) { this->disconnectFromNetwork(); } + if (this->m_airspace) { this->m_airspace->gracefulShutdown(); } } - CStatusMessage CContextNetwork::connectToNetwork(const CServer &server, uint loginMode) + CStatusMessage CContextNetwork::connectToNetwork(const CServer &server, int loginMode) { if (this->isDebugEnabled()) {CLogMessage(this, CLogCategory::contextSlot()).debug() << Q_FUNC_INFO; } QString msg; diff --git a/src/blackcore/context_network_impl.h b/src/blackcore/context_network_impl.h index 66523e1d0..6d5b86e1e 100644 --- a/src/blackcore/context_network_impl.h +++ b/src/blackcore/context_network_impl.h @@ -80,6 +80,10 @@ namespace BlackCore std::function aircraftSnapshotSlot ) override; + //! \copydoc IRemoteAircraftProvider::disconnectRemoteAircraftProviderSignals + //! \ingroup remoteaircraftprovider + virtual bool disconnectRemoteAircraftProviderSignals(QObject *receiver) override; + //! \copydoc IRemoteAircraftProvider::updateAircraftRendered //! \ingroup remoteaircraftprovider virtual bool updateAircraftRendered(const BlackMisc::Aviation::CCallsign &callsign, bool rendered, const QString &originator) override; @@ -133,7 +137,7 @@ namespace BlackCore virtual BlackMisc::Aviation::CAtcStation getOnlineStationForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const override; //! \copydoc IContextNetwork::connectToNetwork() - virtual BlackMisc::CStatusMessage connectToNetwork(const BlackMisc::Network::CServer &server, uint mode) override; + virtual BlackMisc::CStatusMessage connectToNetwork(const BlackMisc::Network::CServer &server, int mode) override; //! \copydoc IContextNetwork::getConnectedServer virtual BlackMisc::Network::CServer getConnectedServer() const override; diff --git a/src/blackcore/context_network_proxy.cpp b/src/blackcore/context_network_proxy.cpp index 7c1acbeca..f82f795d6 100644 --- a/src/blackcore/context_network_proxy.cpp +++ b/src/blackcore/context_network_proxy.cpp @@ -228,7 +228,7 @@ namespace BlackCore this->m_dBusInterface->callDBus(QLatin1Literal("testAddAircraftParts"), parts, incremental); } - CStatusMessage CContextNetworkProxy::connectToNetwork(const CServer &server, uint loginMode) + CStatusMessage CContextNetworkProxy::connectToNetwork(const CServer &server, int loginMode) { return this->m_dBusInterface->callDBusRet(QLatin1Literal("connectToNetwork"), server, loginMode); } diff --git a/src/blackcore/context_network_proxy.h b/src/blackcore/context_network_proxy.h index 206e09fd2..cbb829a1d 100644 --- a/src/blackcore/context_network_proxy.h +++ b/src/blackcore/context_network_proxy.h @@ -76,7 +76,7 @@ namespace BlackCore virtual BlackMisc::Aviation::CAtcStation getOnlineStationForCallsign(const BlackMisc::Aviation::CCallsign &callsign) const override; //! \copydoc IContextNetwork::connectToNetwork - virtual BlackMisc::CStatusMessage connectToNetwork(const BlackMisc::Network::CServer &server, uint mode) override; + virtual BlackMisc::CStatusMessage connectToNetwork(const BlackMisc::Network::CServer &server, int mode) override; //! \copydoc IContextNetwork::disconnectFromNetwork() virtual BlackMisc::CStatusMessage disconnectFromNetwork() override; diff --git a/src/blackcore/context_simulator_impl.cpp b/src/blackcore/context_simulator_impl.cpp index be34d823f..e4c27a47f 100644 --- a/src/blackcore/context_simulator_impl.cpp +++ b/src/blackcore/context_simulator_impl.cpp @@ -532,21 +532,22 @@ namespace BlackCore // depending on shutdown order, network might already have been deleted emit simulatorPluginChanged(CSimulatorPluginInfo()); - IContextNetwork *networkContext = this->getIContextNetwork(); - Q_ASSERT(networkContext); - Q_ASSERT(networkContext->isLocalObject()); - Q_UNUSED(networkContext); + Q_ASSERT(this->getIContextNetwork()); + Q_ASSERT(this->getIContextNetwork()->isLocalObject()); Q_ASSERT(m_simulatorPlugin->simulator); + // disconnect from simulator + if (m_simulatorPlugin->simulator->isConnected()) + { + m_simulatorPlugin->simulator->disconnectFrom(); + } + + // disconnect signals + this->getRuntime()->getCContextNetwork()->disconnectRemoteAircraftProviderSignals(m_simulatorPlugin->simulator); m_simulatorPlugin->simulator->disconnect(); CLogHandler::instance()->disconnect(m_simulatorPlugin->simulator); this->disconnect(m_simulatorPlugin->simulator); - if (m_simulatorPlugin->simulator->isConnected()) - { - m_simulatorPlugin->simulator->disconnectFrom(); // disconnect from simulator - } - m_simulatorPlugin->simulator->deleteLater(); m_simulatorPlugin->simulator = nullptr; m_simulatorPlugin = nullptr; diff --git a/src/blackcore/simulator_common.cpp b/src/blackcore/simulator_common.cpp index 552da8dc4..d2ee55cbc 100644 --- a/src/blackcore/simulator_common.cpp +++ b/src/blackcore/simulator_common.cpp @@ -31,10 +31,9 @@ namespace BlackCore m_simulatorPluginInfo(info) { this->setObjectName(info.getIdentifier()); - this->m_oneSecondTimer = new QTimer(this); - this->m_oneSecondTimer->setObjectName(this->objectName().append(":m_oneSecondTimer")); - connect(this->m_oneSecondTimer, &QTimer::timeout, this, &CSimulatorCommon::ps_oneSecondTimer); - this->m_oneSecondTimer->start(1000); + this->m_oneSecondTimer.setObjectName(this->objectName().append(":m_oneSecondTimer")); + connect(&m_oneSecondTimer, &QTimer::timeout, this, &CSimulatorCommon::ps_oneSecondTimer); + this->m_oneSecondTimer.start(1000); // provider signals bool c = remoteAircraftProvider->connectRemoteAircraftProviderSignals( diff --git a/src/blackcore/simulator_common.h b/src/blackcore/simulator_common.h index f671ff7f6..c676fdbb3 100644 --- a/src/blackcore/simulator_common.h +++ b/src/blackcore/simulator_common.h @@ -135,7 +135,7 @@ namespace BlackCore IInterpolator *m_interpolator = nullptr; //!< interpolator instance qint64 m_highlightEndTimeMsEpoch = 0; //!< end highlighting int m_timerCounter = 0; //!< allows to calculate n seconds - QTimer *m_oneSecondTimer = nullptr; //!< timer + QTimer m_oneSecondTimer{this}; //!< timer BlackMisc::Simulation::CSimulatorPluginInfo m_simulatorPluginInfo; //!< info object BlackMisc::Simulation::CSimulatorSetup m_simulatorSetup; //!< setup object BlackMisc::Simulation::CSimulatedAircraftList m_highlightedAircraft; //!< all other aircraft are to be ignored diff --git a/src/blackmisc/simulation/remoteaircraftprovider.h b/src/blackmisc/simulation/remoteaircraftprovider.h index 5dd293ee6..2e8f6b916 100644 --- a/src/blackmisc/simulation/remoteaircraftprovider.h +++ b/src/blackmisc/simulation/remoteaircraftprovider.h @@ -27,6 +27,7 @@ namespace BlackMisc //! Direct thread safe in memory access to remote aircraft //! \note Can not be derived from QObject (as for the signals), as this would create multiple //! inheritance. Hence Q_DECLARE_INTERFACE is used. + //! \ingroup remoteaircraftprovider class BLACKMISC_EXPORT IRemoteAircraftProvider { public: @@ -106,6 +107,10 @@ namespace BlackMisc std::function aircraftSnapshot ) = 0; + //! Disconnect signals from receiver. As the interface is no QObject, slots can not be connected directly. + virtual bool disconnectRemoteAircraftProviderSignals( + QObject *receiver + ) = 0; }; //! Class which can be directly used to access an \sa IRemoteAircraftProvider object diff --git a/src/blackmisc/simulation/remoteaircraftproviderdummy.cpp b/src/blackmisc/simulation/remoteaircraftproviderdummy.cpp index 60a9c68b9..8d1d65be6 100644 --- a/src/blackmisc/simulation/remoteaircraftproviderdummy.cpp +++ b/src/blackmisc/simulation/remoteaircraftproviderdummy.cpp @@ -80,6 +80,12 @@ namespace BlackMisc return s1 && s2 && s3 && s4; } + bool CRemoteAircraftProviderDummy::disconnectRemoteAircraftProviderSignals(QObject *receiver) + { + if (!receiver) { return false; } + return this->disconnect(receiver); + } + bool CRemoteAircraftProviderDummy::updateAircraftEnabled(const CCallsign &callsign, bool enabledForRendering, const QString &originator) { Q_UNUSED(originator); diff --git a/src/blackmisc/simulation/remoteaircraftproviderdummy.h b/src/blackmisc/simulation/remoteaircraftproviderdummy.h index 7a90033d4..6535f2c02 100644 --- a/src/blackmisc/simulation/remoteaircraftproviderdummy.h +++ b/src/blackmisc/simulation/remoteaircraftproviderdummy.h @@ -67,6 +67,9 @@ namespace BlackMisc std::function aircraftSnapshotSlot ) override; + //! \copydoc IRemoteAircraftProvider::disconnectRemoteAircraftProviderSignals + virtual bool disconnectRemoteAircraftProviderSignals(QObject *receiver) override; + //! \copydoc IRemoteAircraftProvider::updateAircraftEnabled virtual bool updateAircraftEnabled(const BlackMisc::Aviation::CCallsign &callsign, bool enabledForRendering, const QString &originator) override;