From 89f471736dbdb61445f7551b03b66bc62728c6ec Mon Sep 17 00:00:00 2001 From: acetone Date: Thu, 4 May 2023 22:21:57 +0300 Subject: [PATCH] graceful shutdown by SIGINT --- src/httpserver.cpp | 16 ++++++++++++- src/httpserver.h | 7 ++++++ src/ircnetworkclient.cpp | 11 +++++++-- src/ircnetworkclient.h | 3 ++- src/ircnetworkclientstarter.cpp | 16 +++++++++---- src/ircnetworkclientstarter.h | 2 +- src/libirc/libircclient/network.cpp | 36 +++++++++++++++++++++++++---- src/libirc/libircclient/network.h | 11 ++++++++- src/main.cpp | 8 +++++-- 9 files changed, 93 insertions(+), 17 deletions(-) diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 53fdef5..6fcb6ba 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -24,6 +24,7 @@ along with this program. If not, see . #include #include +#include HttpServer::HttpServer(QObject *parent) : QTcpServer(parent) { @@ -36,9 +37,21 @@ HttpServer::HttpServer(QObject *parent) : QTcpServer(parent) } qInfo().noquote() << "[WebUI] HTTP server started at" << Config::webUiAddress() + ":" + QString::number( Config::webUiPort() ); qInfo().noquote() << "[WebUI] HTTP server threads:" << m_pool->maxThreadCount(); + + connect (this, &HttpServer::doStopPrivate, this, &HttpServer::stopPrivate, Qt::QueuedConnection); } HttpServer::~HttpServer() +{ + qInfo().noquote() << "[WebUI] Stopped"; +} + +void HttpServer::stop() +{ + emit doStopPrivate(); +} + +void HttpServer::stopPrivate() { if (QTcpServer::isListening()) QTcpServer::close(); @@ -47,9 +60,10 @@ HttpServer::~HttpServer() m_pool->clear(); if (not m_pool->waitForDone(100)) { - qWarning() << "[WebUI] Thread pool of HTTP server not finished at 100ms"; + qWarning() << "[WebUI] Thread pool not finished in 100 ms"; } m_pool->deleteLater(); + m_pool = nullptr; } } diff --git a/src/httpserver.h b/src/httpserver.h index b3270f2..14c959a 100644 --- a/src/httpserver.h +++ b/src/httpserver.h @@ -47,6 +47,13 @@ class HttpServer : public QTcpServer public: HttpServer(QObject* parent = nullptr); ~HttpServer(); + void stop(); + +signals: + void doStopPrivate(); + +private slots: + void stopPrivate(); protected: void incomingConnection(qintptr handle); diff --git a/src/ircnetworkclient.cpp b/src/ircnetworkclient.cpp index 487c8d9..c4cdd62 100644 --- a/src/ircnetworkclient.cpp +++ b/src/ircnetworkclient.cpp @@ -46,6 +46,11 @@ constexpr const char DIRECT_MESSAGE_TRIGGER_VOICEGATE[] = "voice"; IRCNetworkClient::IRCNetworkClient(QObject *parent) : QObject(parent) {} +IRCNetworkClient::~IRCNetworkClient() +{ + LOG_INFO << "Stopped"; +} + void IRCNetworkClient::setConfig(QSharedPointer config) { if (config->instance != nullptr) @@ -327,7 +332,7 @@ void IRCNetworkClient::Slot_onWelcome() void IRCNetworkClient::Slot_onDisconnected() { - LOG_INFO << "Disconnected from server. Auto reconnect" << (m_config->autoReconnect ? "enabled" : "disabled"); + LOG_INFO << "Disconnected from server. Auto reconnect" << (m_config->autoReconnect ? "enabled" : "disabled") + QString("."); if (m_config->autoReconnect) { QThread::sleep(m_sleepPeriod >= 20 ? m_sleepPeriod : m_sleepPeriod++); @@ -337,9 +342,11 @@ void IRCNetworkClient::Slot_onDisconnected() void IRCNetworkClient::stopPrivate() { + connect (m_network.data(), &libircclient::Network::Event_Disconnected, m_network.data(), &libircclient::Network::stop); + connect (m_network.data(), &libircclient::Network::Event_stopped, this, &IRCNetworkClient::stopped); + m_config->autoReconnect = false; m_network->Disconnect("Shutdowned"); - connect (m_network.data(), &libircclient::Network::Event_Disconnected, this, [&](){ emit stopped(); }); } void IRCNetworkClient::processVoiceRequest(const QString& sender) diff --git a/src/ircnetworkclient.h b/src/ircnetworkclient.h index 03e09c4..e29e73b 100644 --- a/src/ircnetworkclient.h +++ b/src/ircnetworkclient.h @@ -34,6 +34,7 @@ class IRCNetworkClient : public QObject Q_OBJECT public: IRCNetworkClient(QObject* parent = nullptr); + ~IRCNetworkClient(); void setConfig(QSharedPointer config); // after config change; voiceGate have effect in run-time automatically uint reloadChannelList(); @@ -82,6 +83,6 @@ private: QMutex m_mtxNetworkChannelsIteration; QMutex m_mtxvoiceGateRequestsTimestamp; - uint8_t m_sleepPeriod = 1; + uint8_t m_sleepPeriod = 1; // reconnect timer }; diff --git a/src/ircnetworkclientstarter.cpp b/src/ircnetworkclientstarter.cpp index 0c8f30b..b33fa5d 100644 --- a/src/ircnetworkclientstarter.cpp +++ b/src/ircnetworkclientstarter.cpp @@ -24,7 +24,7 @@ along with this program. If not, see . #include #include -QList> IRCNetworkClientStarter::m_instanses; +QList, QThread*>> IRCNetworkClientStarter::m_instanses; void IRCNetworkClientStarter::run() { @@ -40,9 +40,9 @@ void IRCNetworkClientStarter::run() QThread* thread = new QThread; network->moveToThread(thread); network->setConfig(config); - m_instanses.push_back(network); + m_instanses.push_back( {network, thread} ); QObject::connect(thread, &QThread::started, network.data(), &IRCNetworkClient::start); - QObject::connect(network.data(), &IRCNetworkClient::stopped, thread, &QThread::terminate); + QObject::connect(network.data(), &IRCNetworkClient::stopped, thread, &QThread::quit, Qt::DirectConnection); thread->start(); qDebug().noquote() << "["+config->networkName+"]" << "Thread started"; } @@ -52,9 +52,15 @@ void IRCNetworkClientStarter::stop() { foreach (auto inst, m_instanses) { - inst->stop(); - qDebug().noquote() << "["+inst->m_config->networkName+"]" << "Shutdown requested"; + inst.first->stop(); + qDebug().noquote() << "["+inst.first->m_config->networkName+"]" << "Shutdown requested"; QApplication::sync(); + + if (not inst.second->wait(1000)) + { + qWarning().noquote() << "[Core] IRC network client thread not stopped properly in 1000 ms"; + } + inst.second->deleteLater(); } m_instanses.clear(); } diff --git a/src/ircnetworkclientstarter.h b/src/ircnetworkclientstarter.h index cc67a31..c79b8aa 100644 --- a/src/ircnetworkclientstarter.h +++ b/src/ircnetworkclientstarter.h @@ -32,6 +32,6 @@ public: static void stop(); private: - static QList> m_instanses; + static QList, QThread*>> m_instanses; }; diff --git a/src/libirc/libircclient/network.cpp b/src/libirc/libircclient/network.cpp index f643ed8..bd2b835 100644 --- a/src/libirc/libircclient/network.cpp +++ b/src/libirc/libircclient/network.cpp @@ -10,9 +10,12 @@ // Copyright (c) Petr Bena 2015 - 2019 +// Modified for IRCaBot project by acetone, 2023 + #include #include #include +#include #include "network.h" #include "server.h" #include "channel.h" @@ -53,20 +56,26 @@ Network::Network(libirc::ServerAddress &server, const QString &name, const Encod this->channelsToJoin.append(channel); } } + + connect(this, &Network::Event_doStopPrivate, this, &Network::onStopPrivate, Qt::QueuedConnection); } Network::Network(const QHash &hash) : libirc::Network("") { this->initialize(); this->LoadHash(hash); + + connect(this, &Network::Event_doStopPrivate, this, &Network::onStopPrivate, Qt::QueuedConnection); } Network::~Network() { - delete this->server; - this->deleteTimers(); - delete this->socket; - this->freemm(); + stop(); +} + +void Network::stop() +{ + emit Event_doStopPrivate(); } void Network::Connect() @@ -754,6 +763,25 @@ QHash Network::ToHash() return hash; } +void Network::onStopPrivate() +{ + if (this->server) + { + delete this->server; + this->server = nullptr; + } + this->deleteTimers(); + if (this->socket) + { + delete this->socket; + this->socket = nullptr; + } + this->freemm(); + + emit Event_stopped(); + QThread::msleep(10); +} + // This is a slot so don't change the signature to const QList &errors void Network::OnSslHandshakeFailure(QList errors) { diff --git a/src/libirc/libircclient/network.h b/src/libirc/libircclient/network.h index c1349d0..6eecafb 100644 --- a/src/libirc/libircclient/network.h +++ b/src/libirc/libircclient/network.h @@ -10,6 +10,8 @@ // Copyright (c) Petr Bena 2015 - 2019 +// Modified for IRCaBot project by acetone, 2023 + #ifndef NETWORK_H #define NETWORK_H @@ -25,7 +27,6 @@ #include #include #include -#include "../libirc/irc_standards.h" class QTcpSocket; @@ -67,6 +68,7 @@ namespace libircclient Network(libirc::ServerAddress &server, const QString &name, const Encoding &enc = EncodingDefault); Network(const QHash &hash); ~Network() override; + void stop(); virtual void Connect(); virtual void Reconnect(); virtual void Disconnect(QString reason = ""); @@ -305,6 +307,13 @@ namespace libircclient void Event_CAP_Timeout(); void Event_CAP_RequestedCapNotSupported(QString name); + // Shutdown + void Event_doStopPrivate(); + void Event_stopped(); + + private slots: + void onStopPrivate(); + protected slots: virtual void OnSslHandshakeFailure(QList errors); virtual void OnError(QAbstractSocket::SocketError er); diff --git a/src/main.cpp b/src/main.cpp index 7df3cdf..2f2aff2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,7 +39,10 @@ void signalHandler(int SIGNAL) { if (SIGNAL == SIGINT) { - qInfo() << "SIGINT handling..."; + qInfo().noquote() << ""; + qInfo().noquote() << "SIGINT handling..."; + webUi->stop(); + QApplication::sync(); webUi->deleteLater(); IRCNetworkClientStarter::stop(); QApplication::sync(); @@ -118,7 +121,8 @@ int main(int argc, char *argv[]) " _ ___ __ __ ___ ___ _____ _ ___\n" "| | | |_) / /` / /\\ | |_) / / \\ | | \\ \\ / ) )\n" "|_| |_| \\ \\_\\_, /_/--\\ |_|_) \\_\\_/ |_| \\_\\/ _)_)\n" - << info::SOURCE_CODE << " " << info::VERSION << "\n" <