From c8c2fbe07f1a5475aea3a2680af9130558c7e5c8 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Wed, 6 Mar 2013 22:16:05 -0500 Subject: [PATCH] Shutdown cleanup prep-work Create a boost::thread_group object at the qt/bitcoind main-loop level that will hold pointers to all the main-loop threads. This will replace the vnThreadsRunning[] array. For testing, ported the BitcoinMiner threads to use its own boost::thread_group. --- src/init.cpp | 21 +++++++++- src/init.h | 3 +- src/main.cpp | 102 +++++++++++++-------------------------------- src/net.cpp | 2 +- src/net.h | 1 - src/qt/bitcoin.cpp | 6 ++- src/util.cpp | 9 ++-- src/util.h | 3 +- 8 files changed, 64 insertions(+), 83 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index aac46d48..a5015adc 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -122,6 +122,16 @@ void Shutdown(void* parg) } } +// +// Signal handlers are very limited in what they are allowed to do, so: +// +void DetectShutdownThread(boost::thread_group* threadGroup) +{ + while (fRequestShutdown == false) + Sleep(200); + threadGroup->interrupt_all(); +} + void HandleSIGTERM(int) { fRequestShutdown = true; @@ -143,6 +153,7 @@ void HandleSIGHUP(int) #if !defined(QT_GUI) bool AppInit(int argc, char* argv[]) { + boost::thread_group threadGroup; bool fRet = false; try { @@ -185,7 +196,7 @@ bool AppInit(int argc, char* argv[]) exit(ret); } - fRet = AppInit2(); + fRet = AppInit2(threadGroup); } catch (std::exception& e) { PrintExceptionContinue(&e, "AppInit()"); @@ -193,7 +204,11 @@ bool AppInit(int argc, char* argv[]) PrintExceptionContinue(NULL, "AppInit()"); } if (!fRet) + { Shutdown(NULL); + threadGroup.interrupt_all(); + threadGroup.join_all(); + } return fRet; } @@ -405,7 +420,7 @@ void ThreadImport(void *data) { /** Initialize bitcoin. * @pre Parameters should be parsed and config file should be read. */ -bool AppInit2() +bool AppInit2(boost::thread_group& threadGroup) { // ********************************************************* Step 1: setup #ifdef _MSC_VER @@ -449,6 +464,8 @@ bool AppInit2() sigaction(SIGHUP, &sa_hup, NULL); #endif + threadGroup.create_thread(boost::bind(&DetectShutdownThread, &threadGroup)); + // ********************************************************* Step 2: parameter interactions fTestNet = GetBoolArg("-testnet"); diff --git a/src/init.h b/src/init.h index 8308ee64..8986ff62 100644 --- a/src/init.h +++ b/src/init.h @@ -7,11 +7,12 @@ #include "wallet.h" +class boost::thread_group; extern CWallet* pwalletMain; void StartShutdown(); void Shutdown(void* parg); -bool AppInit2(); +bool AppInit2(boost::thread_group& threadGroup); std::string HelpMessage(); #endif diff --git a/src/main.cpp b/src/main.cpp index 60593c0d..df9ea444 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,8 +61,8 @@ CScript COINBASE_FLAGS; const string strMessageMagic = "Bitcoin Signed Message:\n"; -double dHashesPerSec; -int64 nHPSTimerStart; +double dHashesPerSec = 0.0; +int64 nHPSTimerStart = 0; // Settings int64 nTransactionFee = 0; @@ -4089,6 +4089,8 @@ unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1 nHashesDone = 0xffff+1; return (unsigned int) -1; } + if ((nNonce & 0xfff) == 0) + boost::this_thread::interruption_point(); } } @@ -4506,37 +4508,19 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) return true; } -void static ThreadBitcoinMiner(void* parg); - -static bool fGenerateBitcoins = false; -static bool fLimitProcessors = false; -static int nLimitProcessors = -1; - void static BitcoinMiner(CWallet *pwallet) { printf("BitcoinMiner started\n"); SetThreadPriority(THREAD_PRIORITY_LOWEST); - - // Make this thread recognisable as the mining thread RenameThread("bitcoin-miner"); // Each thread has its own key and counter CReserveKey reservekey(pwallet); unsigned int nExtraNonce = 0; - while (fGenerateBitcoins) - { - if (fShutdown) - return; - while (vNodes.empty() || IsInitialBlockDownload()) - { + try { loop { + while (vNodes.empty()) Sleep(1000); - if (fShutdown) - return; - if (!fGenerateBitcoins) - return; - } - // // Create new block @@ -4553,7 +4537,6 @@ void static BitcoinMiner(CWallet *pwallet) printf("Running BitcoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(), ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - // // Pre-build hash buffers // @@ -4626,19 +4609,14 @@ void static BitcoinMiner(CWallet *pwallet) if (GetTime() - nLogTime > 30 * 60) { nLogTime = GetTime(); - printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0); + printf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0); } } } } // Check for stop or if block needs to be rebuilt - if (fShutdown) - return; - if (!fGenerateBitcoins) - return; - if (fLimitProcessors && vnThreadsRunning[THREAD_MINER] > nLimitProcessors) - return; + boost::this_thread::interruption_point(); if (vNodes.empty()) break; if (nBlockNonce >= 0xffff0000) @@ -4658,57 +4636,35 @@ void static BitcoinMiner(CWallet *pwallet) hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); } } - } -} - -void static ThreadBitcoinMiner(void* parg) -{ - CWallet* pwallet = (CWallet*)parg; - try + } } + catch (boost::thread_interrupted) { - vnThreadsRunning[THREAD_MINER]++; - BitcoinMiner(pwallet); - vnThreadsRunning[THREAD_MINER]--; - } - catch (std::exception& e) { - vnThreadsRunning[THREAD_MINER]--; - PrintException(&e, "ThreadBitcoinMiner()"); - } catch (...) { - vnThreadsRunning[THREAD_MINER]--; - PrintException(NULL, "ThreadBitcoinMiner()"); - } - nHPSTimerStart = 0; - if (vnThreadsRunning[THREAD_MINER] == 0) - dHashesPerSec = 0; - printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINER]); + printf("BitcoinMiner terminated\n"); + throw; + } } - void GenerateBitcoins(bool fGenerate, CWallet* pwallet) { - fGenerateBitcoins = fGenerate; - nLimitProcessors = GetArg("-genproclimit", -1); - if (nLimitProcessors == 0) - fGenerateBitcoins = false; - fLimitProcessors = (nLimitProcessors != -1); + static boost::thread_group* minerThreads = NULL; + + int nThreads = GetArg("-genproclimit", -1); + if (nThreads < 0) + nThreads = boost::thread::hardware_concurrency(); - if (fGenerate) + if (minerThreads != NULL) { - int nProcessors = boost::thread::hardware_concurrency(); - printf("%d processors\n", nProcessors); - if (nProcessors < 1) - nProcessors = 1; - if (fLimitProcessors && nProcessors > nLimitProcessors) - nProcessors = nLimitProcessors; - int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINER]; - printf("Starting %d BitcoinMiner threads\n", nAddThreads); - for (int i = 0; i < nAddThreads; i++) - { - if (!NewThread(ThreadBitcoinMiner, pwallet)) - printf("Error: NewThread(ThreadBitcoinMiner) failed\n"); - Sleep(10); - } + minerThreads->interrupt_all(); + delete minerThreads; + minerThreads = NULL; } + + if (nThreads == 0 || !fGenerate) + return; + + minerThreads = new boost::thread_group(); + for (int i = 0; i < nThreads; i++) + minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); } // Amount compression: diff --git a/src/net.cpp b/src/net.cpp index 669f44b6..097f480b 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -2052,6 +2052,7 @@ void StartNode(void* parg) bool StopNode() { printf("StopNode()\n"); + GenerateBitcoins(false, NULL); fShutdown = true; nTransactionsUpdated++; int64 nStart = GetTime(); @@ -2072,7 +2073,6 @@ bool StopNode() if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n"); if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n"); if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n"); - if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n"); if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n"); if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n"); #ifdef USE_UPNP diff --git a/src/net.h b/src/net.h index 368e4cd4..66e528ac 100644 --- a/src/net.h +++ b/src/net.h @@ -75,7 +75,6 @@ enum threadId THREAD_SOCKETHANDLER, THREAD_OPENCONNECTIONS, THREAD_MESSAGEHANDLER, - THREAD_MINER, THREAD_RPCLISTENER, THREAD_UPNP, THREAD_DNSSEED, diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 2c47f30e..a805e350 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -11,6 +11,7 @@ #include "guiutil.h" #include "guiconstants.h" #include "init.h" +#include "util.h" #include "ui_interface.h" #include "paymentserver.h" @@ -215,9 +216,10 @@ int main(int argc, char *argv[]) if (GUIUtil::GetStartOnSystemStartup()) GUIUtil::SetStartOnSystemStartup(true); + boost::thread_group threadGroup; BitcoinGUI window; guiref = &window; - if(AppInit2()) + if(AppInit2(threadGroup)) { { // Put this in a block, so that the Model objects are cleaned up before @@ -259,6 +261,8 @@ int main(int argc, char *argv[]) } // Shutdown the core and its threads, but don't exit Bitcoin-Qt here Shutdown(NULL); + threadGroup.interrupt_all(); + threadGroup.join_all(); } else { diff --git a/src/util.cpp b/src/util.cpp index fc3e846a..ba012d32 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1431,9 +1431,12 @@ void RenameThread(const char* name) // removed. pthread_set_name_np(pthread_self(), name); -// This is XCode 10.6-and-later; bring back if we drop 10.5 support: -// #elif defined(MAC_OSX) -// pthread_setname_np(name); +#elif defined(MAC_OSX) && defined(__MAC_OS_X_VERSION_MAX_ALLOWED) + +// pthread_setname_np is XCode 10.6-and-later +#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 + pthread_setname_np(name); +#endif #else // Prevent warnings for unused parameters... diff --git a/src/util.h b/src/util.h index d129d136..2c261203 100644 --- a/src/util.h +++ b/src/util.h @@ -15,6 +15,8 @@ typedef int pid_t; /* define for Windows compatibility */ #endif #include +#include +#include #include #include @@ -523,4 +525,3 @@ inline uint32_t ByteReverse(uint32_t value) } #endif -