diff options
Diffstat (limited to 'src/init.cpp')
-rw-r--r-- | src/init.cpp | 80 |
1 files changed, 52 insertions, 28 deletions
diff --git a/src/init.cpp b/src/init.cpp index 3d6d04a1ec..39ee9fe60d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -66,7 +66,6 @@ #include <rpc/util.h> #include <scheduler.h> #include <script/sigcache.h> -#include <shutdown.h> #include <sync.h> #include <timedata.h> #include <torcontrol.h> @@ -192,6 +191,16 @@ static void RemovePidFile(const ArgsManager& args) } } +static std::optional<util::SignalInterrupt> g_shutdown; + +void InitContext(NodeContext& node) +{ + assert(!g_shutdown); + g_shutdown.emplace(); + + node.args = &gArgs; + node.shutdown = &*g_shutdown; +} ////////////////////////////////////////////////////////////////////////////// // @@ -204,11 +213,9 @@ static void RemovePidFile(const ArgsManager& args) // The network-processing threads are all part of a thread group // created by AppInit() or the Qt main() function. // -// A clean exit happens when StartShutdown() or the SIGTERM -// signal handler sets ShutdownRequested(), which makes main thread's -// WaitForShutdown() interrupts the thread group. -// And then, WaitForShutdown() makes all other on-going threads -// in the thread group join the main thread. +// A clean exit happens when the SignalInterrupt object is triggered, which +// makes the main thread's SignalInterrupt::wait() call return, and join all +// other ongoing threads in the thread group to the main thread. // Shutdown() is then called to clean up database connections, and stop other // threads that should only be stopped after the main network-processing // threads have exited. @@ -218,6 +225,11 @@ static void RemovePidFile(const ArgsManager& args) // shutdown thing. // +bool ShutdownRequested(node::NodeContext& node) +{ + return bool{*Assert(node.shutdown)}; +} + #if HAVE_SYSTEM static void ShutdownNotify(const ArgsManager& args) { @@ -301,7 +313,7 @@ void Shutdown(NodeContext& node) DumpMempool(*node.mempool, MempoolPath(*node.args)); } - // Drop transactions we were still watching, record fee estimations and Unregister + // Drop transactions we were still watching, record fee estimations and unregister // fee estimator from validation interface. if (node.fee_estimator) { node.fee_estimator->Flush(); @@ -382,7 +394,9 @@ void Shutdown(NodeContext& node) #ifndef WIN32 static void HandleSIGTERM(int) { - StartShutdown(); + // Return value is intentionally ignored because there is not a better way + // of handling this failure in a signal handler. + (void)(*Assert(g_shutdown))(); } static void HandleSIGHUP(int) @@ -392,7 +406,10 @@ static void HandleSIGHUP(int) #else static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType) { - StartShutdown(); + if (!(*Assert(g_shutdown))()) { + LogPrintf("Error: failed to send shutdown signal on Ctrl-C\n"); + return false; + } Sleep(INFINITE); return true; } @@ -689,8 +706,9 @@ static bool AppInitServers(NodeContext& node) const ArgsManager& args = *Assert(node.args); RPCServer::OnStarted(&OnRPCStarted); RPCServer::OnStopped(&OnRPCStopped); - if (!InitHTTPServer()) + if (!InitHTTPServer(*Assert(node.shutdown))) { return false; + } StartRPC(); node.rpc_interruption_point = RpcInterruptionPoint; if (!StartHTTPRPC(&node)) @@ -1036,13 +1054,14 @@ static bool LockDataDirectory(bool probeOnly) { // Make sure only a single Bitcoin process is using the data directory. const fs::path& datadir = gArgs.GetDataDirNet(); - if (!DirIsWritable(datadir)) { + switch (util::LockDirectory(datadir, ".lock", probeOnly)) { + case util::LockResult::ErrorWrite: return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir))); - } - if (!LockDirectory(datadir, ".lock", probeOnly)) { + case util::LockResult::ErrorLock: return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), fs::PathToString(datadir), PACKAGE_NAME)); - } - return true; + case util::LockResult::Success: return true; + } // no default case, so the compiler can warn about missing cases + assert(false); } bool AppInitSanityChecks(const kernel::Context& kernel) @@ -1129,11 +1148,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) }, std::chrono::minutes{1}); // Check disk space every 5 minutes to avoid db corruption. - node.scheduler->scheduleEvery([&args]{ + node.scheduler->scheduleEvery([&args, &node]{ constexpr uint64_t min_disk_space = 50 << 20; // 50 MB if (!CheckDiskSpace(args.GetBlocksDirPath(), min_disk_space)) { LogPrintf("Shutting down due to lack of disk space!\n"); - StartShutdown(); + if (!(*Assert(node.shutdown))()) { + LogPrintf("Error: failed to send shutdown signal after disk space check\n"); + } } }, std::chrono::minutes{5}); @@ -1420,7 +1441,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 7: load block chain - node.notifications = std::make_unique<KernelNotifications>(node.exit_status); + node.notifications = std::make_unique<KernelNotifications>(*Assert(node.shutdown), node.exit_status); ReadNotificationArgs(args, *node.notifications); fReindex = args.GetBoolArg("-reindex", false); bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false); @@ -1471,10 +1492,10 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024)); - for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) { + for (bool fLoaded = false; !fLoaded && !ShutdownRequested(node);) { node.mempool = std::make_unique<CTxMemPool>(mempool_opts); - node.chainman = std::make_unique<ChainstateManager>(node.kernel->interrupt, chainman_opts, blockman_opts); + node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown), chainman_opts, blockman_opts); ChainstateManager& chainman = *node.chainman; // This is defined and set here instead of inline in validation.h to avoid a hard @@ -1504,7 +1525,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS); options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL); options.require_full_verification = args.IsArgSet("-checkblocks") || args.IsArgSet("-checklevel"); - options.check_interrupt = ShutdownRequested; options.coins_error_cb = [] { uiInterface.ThreadSafeMessageBox( _("Error reading from database, shutting down."), @@ -1539,7 +1559,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) return InitError(error); } - if (!fLoaded && !ShutdownRequested()) { + if (!fLoaded && !ShutdownRequested(node)) { // first suggest a reindex if (!options.reindex) { bool fRet = uiInterface.ThreadSafeQuestion( @@ -1548,7 +1568,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT); if (fRet) { fReindex = true; - AbortShutdown(); + if (!Assert(node.shutdown)->reset()) { + LogPrintf("Internal error: failed to reset shutdown signal.\n"); + } } else { LogPrintf("Aborted block database rebuild. Exiting.\n"); return false; @@ -1562,7 +1584,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // As LoadBlockIndex can take several minutes, it's possible the user // requested to kill the GUI during the last operation. If so, exit. // As the program has not fully started yet, Shutdown() is possibly overkill. - if (ShutdownRequested()) { + if (ShutdownRequested(node)) { LogPrintf("Shutdown requested. Exiting.\n"); return false; } @@ -1683,7 +1705,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) ImportBlocks(chainman, vImportFiles); if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { LogPrintf("Stopping after block import\n"); - StartShutdown(); + if (!(*Assert(node.shutdown))()) { + LogPrintf("Error: failed to send shutdown signal after finishing block import\n"); + } return; } @@ -1703,16 +1727,16 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // Wait for genesis block to be processed { WAIT_LOCK(g_genesis_wait_mutex, lock); - // We previously could hang here if StartShutdown() is called prior to + // We previously could hang here if shutdown was requested prior to // ImportBlocks getting started, so instead we just wait on a timer to // check ShutdownRequested() regularly. - while (!fHaveGenesis && !ShutdownRequested()) { + while (!fHaveGenesis && !ShutdownRequested(node)) { g_genesis_wait_cv.wait_for(lock, std::chrono::milliseconds(500)); } block_notify_genesis_wait_connection.disconnect(); } - if (ShutdownRequested()) { + if (ShutdownRequested(node)) { return false; } |