From 41106a50d2be9358ab19e75c1d6d075a773525b7 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 23 Apr 2014 08:40:48 +0200 Subject: [PATCH] qt: get required locks upfront in polling functions This avoids the GUI from getting stuck on periodical polls if the core is holding the locks for a longer time - for example, during a wallet rescan. --- src/qt/clientmodel.cpp | 6 ++++++ src/qt/transactiontablemodel.cpp | 21 ++++++++++++++------- src/qt/walletmodel.cpp | 25 ++++++++++++++----------- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 287296644c2..3c0564c2081 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -92,6 +92,12 @@ double ClientModel::getVerificationProgress() const void ClientModel::updateTimer() { + // Get required lock upfront. This avoids the GUI from getting stuck on + // periodical polls if the core is holding the locks for a longer time - + // for example, during a wallet rescan. + TRY_LOCK(cs_main, lockMain); + if(!lockMain) + return; // Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change. // Periodically check and update with a timer. int newNumBlocks = getNumBlocks(); diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index aaecf88c258..df412650d8c 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -24,7 +24,6 @@ #include #include #include -#include // Amount column is right-aligned it contains numbers static int column_alignments[] = { @@ -187,17 +186,25 @@ public: { TransactionRecord *rec = &cachedWallet[idx]; + // Get required locks upfront. This avoids the GUI from getting + // stuck if the core is holding the locks for a longer time - for + // example, during a wallet rescan. + // // If a status update is needed (blocks came in since last check), // update the status of this transaction from the wallet. Otherwise, // simply re-use the cached status. - LOCK2(cs_main, wallet->cs_wallet); - if(rec->statusUpdateNeeded()) + TRY_LOCK(cs_main, lockMain); + if(lockMain) { - std::map::iterator mi = wallet->mapWallet.find(rec->hash); - - if(mi != wallet->mapWallet.end()) + TRY_LOCK(wallet->cs_wallet, lockWallet); + if(lockWallet && rec->statusUpdateNeeded()) { - rec->updateStatus(mi->second); + std::map::iterator mi = wallet->mapWallet.find(rec->hash); + + if(mi != wallet->mapWallet.end()) + { + rec->updateStatus(mi->second); + } } } return rec; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 61f26107afc..37d82ec0633 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -98,18 +98,21 @@ void WalletModel::updateStatus() void WalletModel::pollBalanceChanged() { - bool heightChanged = false; - { - LOCK(cs_main); - if(chainActive.Height() != cachedNumBlocks) - { - // Balance and number of transactions might have changed - cachedNumBlocks = chainActive.Height(); - heightChanged = true; - } - } - if(heightChanged) + // Get required locks upfront. This avoids the GUI from getting stuck on + // periodical polls if the core is holding the locks for a longer time - + // for example, during a wallet rescan. + TRY_LOCK(cs_main, lockMain); + if(!lockMain) + return; + TRY_LOCK(wallet->cs_wallet, lockWallet); + if(!lockWallet) + return; + + if(chainActive.Height() != cachedNumBlocks) { + // Balance and number of transactions might have changed + cachedNumBlocks = chainActive.Height(); + checkBalanceChanged(); if(transactionTableModel) transactionTableModel->updateConfirmations();