aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2016-11-18 16:35:14 +0100
committerWladimir J. van der Laan <laanwj@gmail.com>2016-11-23 12:33:36 +0100
commit693384eedb1ac7f449e226edd53e2cb52a86e279 (patch)
tree898d2bc8d3667c56bdd32c656b03f478e305d99f
parent47db07537746940ee7dd0739a8c73e328837813f (diff)
qt: Prevent thread/memory leak on exiting RPCConsole
Make ownership of the QThread object clear, so that the RPCConsole can wait for the executor thread to quit before shutdown is called. This increases overall thread safety, and prevents some objects from leaking on exit.
-rw-r--r--src/qt/bitcoin.cpp8
-rw-r--r--src/qt/bitcoingui.cpp11
-rw-r--r--src/qt/rpcconsole.cpp24
-rw-r--r--src/qt/rpcconsole.h2
4 files changed, 29 insertions, 16 deletions
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index c828234f44..1434c45dd4 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -409,6 +409,11 @@ void BitcoinApplication::requestInitialize()
void BitcoinApplication::requestShutdown()
{
+ // Show a simple window indicating shutdown status
+ // Do this first as some of the steps may take some time below,
+ // for example the RPC console may still be executing a command.
+ ShutdownWindow::showShutdownWindow(window);
+
qDebug() << __func__ << ": Requesting shutdown";
startThread();
window->hide();
@@ -423,9 +428,6 @@ void BitcoinApplication::requestShutdown()
delete clientModel;
clientModel = 0;
- // Show a simple window indicating shutdown status
- ShutdownWindow::showShutdownWindow(window);
-
// Request shutdown from core thread
Q_EMIT requestedShutdown();
}
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 4d78fd13c0..788fc9af31 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -511,6 +511,13 @@ void BitcoinGUI::setClientModel(ClientModel *_clientModel)
// Disable context menu on tray icon
trayIconMenu->clear();
}
+ // Propagate cleared model to child objects
+ rpcConsole->setClientModel(nullptr);
+#ifdef ENABLE_WALLET
+ walletFrame->setClientModel(nullptr);
+#endif // ENABLE_WALLET
+ unitDisplayControl->setOptionsModel(nullptr);
+ connectionsControl->setClientModel(nullptr);
}
}
@@ -1242,7 +1249,5 @@ void NetworkToggleStatusBarControl::mousePressEvent(QMouseEvent *event)
/** Lets the control know about the Client Model */
void NetworkToggleStatusBarControl::setClientModel(ClientModel *_clientModel)
{
- if (_clientModel) {
- this->clientModel = _clientModel;
- }
+ this->clientModel = _clientModel;
}
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 7f5bb29f16..520d229901 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -382,7 +382,6 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
// based timer interface
RPCSetTimerInterfaceIfUnset(rpcTimerInterface);
- startExecutor();
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
ui->detailWidget->hide();
@@ -396,7 +395,6 @@ RPCConsole::RPCConsole(const PlatformStyle *_platformStyle, QWidget *parent) :
RPCConsole::~RPCConsole()
{
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
- Q_EMIT stopExecutor();
RPCUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface;
delete ui;
@@ -565,6 +563,14 @@ void RPCConsole::setClientModel(ClientModel *model)
autoCompleter = new QCompleter(wordList, this);
ui->lineEdit->setCompleter(autoCompleter);
autoCompleter->popup()->installEventFilter(this);
+ // Start thread to execute RPC commands.
+ startExecutor();
+ }
+ if (!model) {
+ // Client model is being set to 0, this means shutdown() is about to be called.
+ // Make sure we clean up the executor thread
+ Q_EMIT stopExecutor();
+ thread.wait();
}
}
@@ -759,9 +765,8 @@ void RPCConsole::browseHistory(int offset)
void RPCConsole::startExecutor()
{
- QThread *thread = new QThread;
RPCExecutor *executor = new RPCExecutor();
- executor->moveToThread(thread);
+ executor->moveToThread(&thread);
// Replies from executor object must go to this object
connect(executor, SIGNAL(reply(int,QString)), this, SLOT(message(int,QString)));
@@ -769,16 +774,15 @@ void RPCConsole::startExecutor()
connect(this, SIGNAL(cmdRequest(QString)), executor, SLOT(request(QString)));
// On stopExecutor signal
- // - queue executor for deletion (in execution thread)
// - quit the Qt event loop in the execution thread
- connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater()));
- connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit()));
- // Queue the thread for deletion (in this thread) when it is finished
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ connect(this, SIGNAL(stopExecutor()), &thread, SLOT(quit()));
+ // - queue executor for deletion (in execution thread)
+ connect(&thread, SIGNAL(finished()), executor, SLOT(deleteLater()), Qt::DirectConnection);
+ connect(&thread, SIGNAL(finished()), this, SLOT(test()), Qt::DirectConnection);
// Default implementation of QThread::run() simply spins up an event loop in the thread,
// which is what we want.
- thread->start();
+ thread.start();
}
void RPCConsole::on_tabWidget_currentChanged(int index)
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 8c20379a8c..344d5ecb98 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -12,6 +12,7 @@
#include <QWidget>
#include <QCompleter>
+#include <QThread>
class ClientModel;
class PlatformStyle;
@@ -148,6 +149,7 @@ private:
QMenu *banTableContextMenu;
int consoleFontSize;
QCompleter *autoCompleter;
+ QThread thread;
/** Update UI with latest network info from model. */
void updateNetworkState();