Changeset View
Changeset View
Standalone View
Standalone View
src/init.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2018 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#if defined(HAVE_CONFIG_H) | #if defined(HAVE_CONFIG_H) | ||||
#include <config/bitcoin-config.h> | #include <config/bitcoin-config.h> | ||||
#endif | #endif | ||||
#include <init.h> | #include <init.h> | ||||
Show All 20 Lines | |||||
#include <policy/policy.h> | #include <policy/policy.h> | ||||
#include <rpc/blockchain.h> | #include <rpc/blockchain.h> | ||||
#include <rpc/register.h> | #include <rpc/register.h> | ||||
#include <rpc/server.h> | #include <rpc/server.h> | ||||
#include <scheduler.h> | #include <scheduler.h> | ||||
#include <script/scriptcache.h> | #include <script/scriptcache.h> | ||||
#include <script/sigcache.h> | #include <script/sigcache.h> | ||||
#include <script/standard.h> | #include <script/standard.h> | ||||
#include <shutdown.h> | |||||
#include <timedata.h> | #include <timedata.h> | ||||
#include <torcontrol.h> | #include <torcontrol.h> | ||||
#include <txdb.h> | #include <txdb.h> | ||||
#include <txmempool.h> | #include <txmempool.h> | ||||
#include <ui_interface.h> | #include <ui_interface.h> | ||||
#include <util/moneystr.h> | #include <util/moneystr.h> | ||||
#include <util/system.h> | #include <util/system.h> | ||||
#include <validation.h> | #include <validation.h> | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | |||||
// | // | ||||
// Thread management and startup/shutdown: | // Thread management and startup/shutdown: | ||||
// | // | ||||
// The network-processing threads are all part of a thread group created by | // The network-processing threads are all part of a thread group created by | ||||
// AppInit() or the Qt main() function. | // AppInit() or the Qt main() function. | ||||
// | // | ||||
// A clean exit happens when StartShutdown() or the SIGTERM signal handler sets | // A clean exit happens when StartShutdown() or the SIGTERM signal handler sets | ||||
// fRequestShutdown, which triggers the DetectShutdownThread(), which interrupts | // ShutdownRequested(), which triggers the DetectShutdownThread(), which | ||||
// the main thread group. DetectShutdownThread() then exits, which causes | // interrupts the main thread group. DetectShutdownThread() then exits, which | ||||
// AppInit() to continue (it .joins the shutdown thread). Shutdown() is then | // causes AppInit() to continue (it .joins the shutdown thread). Shutdown() is | ||||
// called to clean up database connections, and stop other threads that should | // then called to clean up database connections, and stop other threads that | ||||
// only be stopped after the main network-processing threads have exited. | // should only be stopped after the main network-processing threads have exited. | ||||
// | // | ||||
// Shutdown for Qt is very similar, only it uses a QTimer to detect | // Shutdown for Qt is very similar, only it uses a QTimer to detect | ||||
// fRequestShutdown getting set, and then does the normal Qt shutdown thing. | // ShutdownRequested() getting set, and then does the normal Qt shutdown thing. | ||||
// | // | ||||
std::atomic<bool> fRequestShutdown(false); | |||||
void StartShutdown() { | |||||
fRequestShutdown = true; | |||||
} | |||||
bool ShutdownRequested() { | |||||
return fRequestShutdown; | |||||
} | |||||
/** | /** | ||||
* This is a minimally invasive approach to shutdown on LevelDB read errors from | * This is a minimally invasive approach to shutdown on LevelDB read errors from | ||||
* the chainstate, while keeping user interface out of the common library, which | * the chainstate, while keeping user interface out of the common library, which | ||||
* is shared between bitcoind, and bitcoin-qt and non-server tools. | * is shared between bitcoind, and bitcoin-qt and non-server tools. | ||||
*/ | */ | ||||
class CCoinsViewErrorCatcher final : public CCoinsViewBacked { | class CCoinsViewErrorCatcher final : public CCoinsViewBacked { | ||||
public: | public: | ||||
explicit CCoinsViewErrorCatcher(CCoinsView *view) | explicit CCoinsViewErrorCatcher(CCoinsView *view) | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Signal handlers are very limited in what they are allowed to do. | * Signal handlers are very limited in what they are allowed to do. | ||||
* The execution context the handler is invoked in is not guaranteed, | * The execution context the handler is invoked in is not guaranteed, | ||||
* so we restrict handler operations to just touching variables: | * so we restrict handler operations to just touching variables: | ||||
*/ | */ | ||||
#ifndef WIN32 | #ifndef WIN32 | ||||
static void HandleSIGTERM(int) { | static void HandleSIGTERM(int) { | ||||
fRequestShutdown = true; | StartShutdown(); | ||||
} | } | ||||
static void HandleSIGHUP(int) { | static void HandleSIGHUP(int) { | ||||
GetLogger().m_reopen_file = true; | GetLogger().m_reopen_file = true; | ||||
} | } | ||||
#else | #else | ||||
static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) { | static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) { | ||||
fRequestShutdown = true; | StartShutdown(); | ||||
Sleep(INFINITE); | Sleep(INFINITE); | ||||
return true; | return true; | ||||
} | } | ||||
#endif | #endif | ||||
#ifndef WIN32 | #ifndef WIN32 | ||||
static void registerSignalHandler(int signal, void (*handler)(int)) { | static void registerSignalHandler(int signal, void (*handler)(int)) { | ||||
struct sigaction sa; | struct sigaction sa; | ||||
▲ Show 20 Lines • Show All 891 Lines • ▼ Show 20 Lines | ScheduleBatchPriority(); | ||||
LogPrintf("Stopping after block import\n"); | LogPrintf("Stopping after block import\n"); | ||||
StartShutdown(); | StartShutdown(); | ||||
return; | return; | ||||
} | } | ||||
} // End scope of CImportingNow | } // End scope of CImportingNow | ||||
if (gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { | if (gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { | ||||
LoadMempool(config, ::g_mempool); | LoadMempool(config, ::g_mempool); | ||||
} | } | ||||
::g_mempool.SetIsLoaded(!fRequestShutdown); | ::g_mempool.SetIsLoaded(!ShutdownRequested()); | ||||
} | } | ||||
/** Sanity checks | /** Sanity checks | ||||
* Ensure that Bitcoin is running in a usable environment with all | * Ensure that Bitcoin is running in a usable environment with all | ||||
* necessary library support. | * necessary library support. | ||||
*/ | */ | ||||
static bool InitSanityCheck() { | static bool InitSanityCheck() { | ||||
if (!ECC_InitSanityCheck()) { | if (!ECC_InitSanityCheck()) { | ||||
▲ Show 20 Lines • Show All 900 Lines • ▼ Show 20 Lines | LogPrintf("* Using %.1fMiB for chain state database\n", | ||||
nCoinDBCache * (1.0 / 1024 / 1024)); | nCoinDBCache * (1.0 / 1024 / 1024)); | ||||
LogPrintf("* Using %.1fMiB for in-memory UTXO set (plus up to %.1fMiB of " | LogPrintf("* Using %.1fMiB for in-memory UTXO set (plus up to %.1fMiB of " | ||||
"unused mempool space)\n", | "unused mempool space)\n", | ||||
nCoinCacheUsage * (1.0 / 1024 / 1024), | nCoinCacheUsage * (1.0 / 1024 / 1024), | ||||
nMempoolSizeMax * (1.0 / 1024 / 1024)); | nMempoolSizeMax * (1.0 / 1024 / 1024)); | ||||
int64_t nStart = 0; | int64_t nStart = 0; | ||||
bool fLoaded = false; | bool fLoaded = false; | ||||
while (!fLoaded && !fRequestShutdown) { | while (!fLoaded && !ShutdownRequested()) { | ||||
bool fReset = fReindex; | bool fReset = fReindex; | ||||
std::string strLoadError; | std::string strLoadError; | ||||
uiInterface.InitMessage(_("Loading block index...")); | uiInterface.InitMessage(_("Loading block index...")); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
nStart = GetTimeMillis(); | nStart = GetTimeMillis(); | ||||
Show All 10 Lines | while (!fLoaded && !ShutdownRequested()) { | ||||
pblocktree->WriteReindexing(true); | pblocktree->WriteReindexing(true); | ||||
// If we're reindexing in prune mode, wipe away unusable | // If we're reindexing in prune mode, wipe away unusable | ||||
// block files and all undo data files | // block files and all undo data files | ||||
if (fPruneMode) { | if (fPruneMode) { | ||||
CleanupBlockRevFiles(); | CleanupBlockRevFiles(); | ||||
} | } | ||||
} | } | ||||
if (fRequestShutdown) { | if (ShutdownRequested()) { | ||||
break; | break; | ||||
} | } | ||||
// LoadBlockIndex will load fHavePruned if we've ever removed a | // LoadBlockIndex will load fHavePruned if we've ever removed a | ||||
// block file from disk. | // block file from disk. | ||||
// Note that it also sets fReindex based on the disk flag! | // Note that it also sets fReindex based on the disk flag! | ||||
// From here on out fReindex and fReset mean something | // From here on out fReindex and fReset mean something | ||||
// different! | // different! | ||||
▲ Show 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | while (!fLoaded && !ShutdownRequested()) { | ||||
LogPrintf("%s\n", e.what()); | LogPrintf("%s\n", e.what()); | ||||
strLoadError = _("Error opening block database"); | strLoadError = _("Error opening block database"); | ||||
break; | break; | ||||
} | } | ||||
fLoaded = true; | fLoaded = true; | ||||
} while (false); | } while (false); | ||||
if (!fLoaded && !fRequestShutdown) { | if (!fLoaded && !ShutdownRequested()) { | ||||
// first suggest a reindex | // first suggest a reindex | ||||
if (!fReset) { | if (!fReset) { | ||||
bool fRet = uiInterface.ThreadSafeQuestion( | bool fRet = uiInterface.ThreadSafeQuestion( | ||||
strLoadError + ".\n\n" + | strLoadError + ".\n\n" + | ||||
_("Do you want to rebuild the block database now?"), | _("Do you want to rebuild the block database now?"), | ||||
strLoadError + ".\nPlease restart with -reindex or " | strLoadError + ".\nPlease restart with -reindex or " | ||||
"-reindex-chainstate to recover.", | "-reindex-chainstate to recover.", | ||||
"", | "", | ||||
CClientUIInterface::MSG_ERROR | | CClientUIInterface::MSG_ERROR | | ||||
CClientUIInterface::BTN_ABORT); | CClientUIInterface::BTN_ABORT); | ||||
if (fRet) { | if (fRet) { | ||||
fReindex = true; | fReindex = true; | ||||
fRequestShutdown = false; | AbortShutdown(); | ||||
} else { | } else { | ||||
LogPrintf("Aborted block database rebuild. Exiting.\n"); | LogPrintf("Aborted block database rebuild. Exiting.\n"); | ||||
return false; | return false; | ||||
} | } | ||||
} else { | } else { | ||||
return InitError(strLoadError); | return InitError(strLoadError); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// As LoadBlockIndex can take several minutes, it's possible the user | // As LoadBlockIndex can take several minutes, it's possible the user | ||||
// requested to kill the GUI during the last operation. If so, exit. | // requested to kill the GUI during the last operation. If so, exit. | ||||
// As the program has not fully started yet, Shutdown() is possibly | // As the program has not fully started yet, Shutdown() is possibly | ||||
// overkill. | // overkill. | ||||
if (fRequestShutdown) { | if (ShutdownRequested()) { | ||||
LogPrintf("Shutdown requested. Exiting.\n"); | LogPrintf("Shutdown requested. Exiting.\n"); | ||||
return false; | return false; | ||||
} | } | ||||
if (fLoaded) { | if (fLoaded) { | ||||
LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart); | LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart); | ||||
} | } | ||||
// Encoded addresses using cashaddr instead of base58. | // Encoded addresses using cashaddr instead of base58. | ||||
▲ Show 20 Lines • Show All 179 Lines • Show Last 20 Lines |