mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 23:09:44 -04:00
Get rid of shutdown.cpp/shutdown.h, use SignalInterrupt directly
This change is mostly a refectoring that removes some code and gets rid of an unnecessary layer of indirection after #27861 But it is not a pure refactoring since StartShutdown, AbortShutdown, and WaitForShutdown functions used to abort on failure, and the replacement code logs or returns errors instead.
This commit is contained in:
parent
213542b625
commit
6db04be102
10 changed files with 47 additions and 121 deletions
|
@ -271,7 +271,6 @@ BITCOIN_CORE_H = \
|
||||||
script/sign.h \
|
script/sign.h \
|
||||||
script/signingprovider.h \
|
script/signingprovider.h \
|
||||||
script/solver.h \
|
script/solver.h \
|
||||||
shutdown.h \
|
|
||||||
signet.h \
|
signet.h \
|
||||||
streams.h \
|
streams.h \
|
||||||
support/allocators/pool.h \
|
support/allocators/pool.h \
|
||||||
|
@ -459,7 +458,6 @@ libbitcoin_node_a_SOURCES = \
|
||||||
rpc/signmessage.cpp \
|
rpc/signmessage.cpp \
|
||||||
rpc/txoutproof.cpp \
|
rpc/txoutproof.cpp \
|
||||||
script/sigcache.cpp \
|
script/sigcache.cpp \
|
||||||
shutdown.cpp \
|
|
||||||
signet.cpp \
|
signet.cpp \
|
||||||
timedata.cpp \
|
timedata.cpp \
|
||||||
torcontrol.cpp \
|
torcontrol.cpp \
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include <node/context.h>
|
#include <node/context.h>
|
||||||
#include <node/interface_ui.h>
|
#include <node/interface_ui.h>
|
||||||
#include <noui.h>
|
#include <noui.h>
|
||||||
#include <shutdown.h>
|
|
||||||
#include <util/check.h>
|
#include <util/check.h>
|
||||||
#include <util/exception.h>
|
#include <util/exception.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
|
@ -185,7 +184,6 @@ static bool AppInit(NodeContext& node)
|
||||||
}
|
}
|
||||||
|
|
||||||
node.kernel = std::make_unique<kernel::Context>();
|
node.kernel = std::make_unique<kernel::Context>();
|
||||||
node.shutdown = &node.kernel->interrupt; // TEMPORARY: will go away when kernel->interrupt member is removed
|
|
||||||
if (!AppInitSanityChecks(*node.kernel))
|
if (!AppInitSanityChecks(*node.kernel))
|
||||||
{
|
{
|
||||||
// InitError will have been called with detailed error, which ends up on console
|
// InitError will have been called with detailed error, which ends up on console
|
||||||
|
@ -273,9 +271,7 @@ MAIN_FUNCTION
|
||||||
if (ProcessInitCommands(args)) return EXIT_SUCCESS;
|
if (ProcessInitCommands(args)) return EXIT_SUCCESS;
|
||||||
|
|
||||||
// Start application
|
// Start application
|
||||||
if (AppInit(node)) {
|
if (!AppInit(node) || !Assert(node.shutdown)->wait()) {
|
||||||
WaitForShutdown();
|
|
||||||
} else {
|
|
||||||
node.exit_status = EXIT_FAILURE;
|
node.exit_status = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
Interrupt(node);
|
Interrupt(node);
|
||||||
|
|
55
src/init.cpp
55
src/init.cpp
|
@ -66,7 +66,6 @@
|
||||||
#include <rpc/util.h>
|
#include <rpc/util.h>
|
||||||
#include <scheduler.h>
|
#include <scheduler.h>
|
||||||
#include <script/sigcache.h>
|
#include <script/sigcache.h>
|
||||||
#include <shutdown.h>
|
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <timedata.h>
|
#include <timedata.h>
|
||||||
#include <torcontrol.h>
|
#include <torcontrol.h>
|
||||||
|
@ -192,9 +191,15 @@ static void RemovePidFile(const ArgsManager& args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::optional<util::SignalInterrupt> g_shutdown;
|
||||||
|
|
||||||
void InitContext(NodeContext& node)
|
void InitContext(NodeContext& node)
|
||||||
{
|
{
|
||||||
|
assert(!g_shutdown);
|
||||||
|
g_shutdown.emplace();
|
||||||
|
|
||||||
node.args = &gArgs;
|
node.args = &gArgs;
|
||||||
|
node.shutdown = &*g_shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -208,11 +213,9 @@ void InitContext(NodeContext& node)
|
||||||
// The network-processing threads are all part of a thread group
|
// The network-processing threads are all part of a thread group
|
||||||
// created by AppInit() or the Qt main() function.
|
// created by AppInit() or the Qt main() function.
|
||||||
//
|
//
|
||||||
// A clean exit happens when StartShutdown() or the SIGTERM
|
// A clean exit happens when the SignalInterrupt object is triggered, which
|
||||||
// signal handler sets ShutdownRequested(), which makes main thread's
|
// makes the main thread's SignalInterrupt::wait() call return, and join all
|
||||||
// WaitForShutdown() interrupts the thread group.
|
// other ongoing threads in the thread group to the main thread.
|
||||||
// And then, WaitForShutdown() makes all other on-going threads
|
|
||||||
// in the thread group join the main thread.
|
|
||||||
// Shutdown() is then called to clean up database connections, and stop other
|
// Shutdown() is then called to clean up database connections, and stop other
|
||||||
// threads that should only be stopped after the main network-processing
|
// threads that should only be stopped after the main network-processing
|
||||||
// threads have exited.
|
// threads have exited.
|
||||||
|
@ -222,6 +225,11 @@ void InitContext(NodeContext& node)
|
||||||
// shutdown thing.
|
// shutdown thing.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
bool ShutdownRequested(node::NodeContext& node)
|
||||||
|
{
|
||||||
|
return bool{*Assert(node.shutdown)};
|
||||||
|
}
|
||||||
|
|
||||||
#if HAVE_SYSTEM
|
#if HAVE_SYSTEM
|
||||||
static void ShutdownNotify(const ArgsManager& args)
|
static void ShutdownNotify(const ArgsManager& args)
|
||||||
{
|
{
|
||||||
|
@ -386,7 +394,9 @@ void Shutdown(NodeContext& node)
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
static void HandleSIGTERM(int)
|
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)
|
static void HandleSIGHUP(int)
|
||||||
|
@ -396,7 +406,10 @@ static void HandleSIGHUP(int)
|
||||||
#else
|
#else
|
||||||
static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType)
|
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);
|
Sleep(INFINITE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1145,11 +1158,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
}, std::chrono::minutes{1});
|
}, std::chrono::minutes{1});
|
||||||
|
|
||||||
// Check disk space every 5 minutes to avoid db corruption.
|
// 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
|
constexpr uint64_t min_disk_space = 50 << 20; // 50 MB
|
||||||
if (!CheckDiskSpace(args.GetBlocksDirPath(), min_disk_space)) {
|
if (!CheckDiskSpace(args.GetBlocksDirPath(), min_disk_space)) {
|
||||||
LogPrintf("Shutting down due to lack of disk space!\n");
|
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});
|
}, std::chrono::minutes{5});
|
||||||
|
|
||||||
|
@ -1487,7 +1502,7 @@ 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));
|
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.mempool = std::make_unique<CTxMemPool>(mempool_opts);
|
||||||
|
|
||||||
node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown), chainman_opts, blockman_opts);
|
node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown), chainman_opts, blockman_opts);
|
||||||
|
@ -1554,7 +1569,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
return InitError(error);
|
return InitError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fLoaded && !ShutdownRequested()) {
|
if (!fLoaded && !ShutdownRequested(node)) {
|
||||||
// first suggest a reindex
|
// first suggest a reindex
|
||||||
if (!options.reindex) {
|
if (!options.reindex) {
|
||||||
bool fRet = uiInterface.ThreadSafeQuestion(
|
bool fRet = uiInterface.ThreadSafeQuestion(
|
||||||
|
@ -1563,7 +1578,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
|
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
|
||||||
if (fRet) {
|
if (fRet) {
|
||||||
fReindex = true;
|
fReindex = true;
|
||||||
AbortShutdown();
|
if (!Assert(node.shutdown)->reset()) {
|
||||||
|
LogPrintf("Internal error: failed to reset shutdown signal.\n");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LogPrintf("Aborted block database rebuild. Exiting.\n");
|
LogPrintf("Aborted block database rebuild. Exiting.\n");
|
||||||
return false;
|
return false;
|
||||||
|
@ -1577,7 +1594,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
// 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 overkill.
|
// As the program has not fully started yet, Shutdown() is possibly overkill.
|
||||||
if (ShutdownRequested()) {
|
if (ShutdownRequested(node)) {
|
||||||
LogPrintf("Shutdown requested. Exiting.\n");
|
LogPrintf("Shutdown requested. Exiting.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1698,7 +1715,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
ImportBlocks(chainman, vImportFiles);
|
ImportBlocks(chainman, vImportFiles);
|
||||||
if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
|
if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
|
||||||
LogPrintf("Stopping after block import\n");
|
LogPrintf("Stopping after block import\n");
|
||||||
StartShutdown();
|
if (!(*Assert(node.shutdown))()) {
|
||||||
|
LogPrintf("Error: failed to send shutdown signal after finishing block import\n");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1718,16 +1737,16 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
// Wait for genesis block to be processed
|
// Wait for genesis block to be processed
|
||||||
{
|
{
|
||||||
WAIT_LOCK(g_genesis_wait_mutex, lock);
|
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
|
// ImportBlocks getting started, so instead we just wait on a timer to
|
||||||
// check ShutdownRequested() regularly.
|
// check ShutdownRequested() regularly.
|
||||||
while (!fHaveGenesis && !ShutdownRequested()) {
|
while (!fHaveGenesis && !ShutdownRequested(node)) {
|
||||||
g_genesis_wait_cv.wait_for(lock, std::chrono::milliseconds(500));
|
g_genesis_wait_cv.wait_for(lock, std::chrono::milliseconds(500));
|
||||||
}
|
}
|
||||||
block_notify_genesis_wait_connection.disconnect();
|
block_notify_genesis_wait_connection.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShutdownRequested()) {
|
if (ShutdownRequested(node)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,10 @@ namespace node {
|
||||||
struct NodeContext;
|
struct NodeContext;
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
|
||||||
/** Initialize node context variables. */
|
/** Initialize node context shutdown and args variables. */
|
||||||
void InitContext(node::NodeContext& node);
|
void InitContext(node::NodeContext& node);
|
||||||
|
/** Return whether node shutdown was requested. */
|
||||||
|
bool ShutdownRequested(node::NodeContext& node);
|
||||||
|
|
||||||
/** Interrupt threads */
|
/** Interrupt threads */
|
||||||
void Interrupt(node::NodeContext& node);
|
void Interrupt(node::NodeContext& node);
|
||||||
|
|
|
@ -14,12 +14,8 @@
|
||||||
|
|
||||||
|
|
||||||
namespace kernel {
|
namespace kernel {
|
||||||
Context* g_context;
|
|
||||||
|
|
||||||
Context::Context()
|
Context::Context()
|
||||||
{
|
{
|
||||||
assert(!g_context);
|
|
||||||
g_context = this;
|
|
||||||
std::string sha256_algo = SHA256AutoDetect();
|
std::string sha256_algo = SHA256AutoDetect();
|
||||||
LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
|
LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
|
||||||
RandomInit();
|
RandomInit();
|
||||||
|
@ -29,8 +25,6 @@ Context::Context()
|
||||||
Context::~Context()
|
Context::~Context()
|
||||||
{
|
{
|
||||||
ECC_Stop();
|
ECC_Stop();
|
||||||
assert(g_context);
|
|
||||||
g_context = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
|
|
|
@ -18,24 +18,9 @@ namespace kernel {
|
||||||
//! State stored directly in this struct should be simple. More complex state
|
//! State stored directly in this struct should be simple. More complex state
|
||||||
//! should be stored to std::unique_ptr members pointing to opaque types.
|
//! should be stored to std::unique_ptr members pointing to opaque types.
|
||||||
struct Context {
|
struct Context {
|
||||||
//! Interrupt object that can be used to stop long-running kernel operations.
|
|
||||||
util::SignalInterrupt interrupt;
|
|
||||||
|
|
||||||
//! Declare default constructor and destructor that are not inline, so code
|
|
||||||
//! instantiating the kernel::Context struct doesn't need to #include class
|
|
||||||
//! definitions for all the unique_ptr members.
|
|
||||||
Context();
|
Context();
|
||||||
~Context();
|
~Context();
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Global pointer to kernel::Context for legacy code. New code should avoid
|
|
||||||
//! using this, and require state it needs to be passed to it directly.
|
|
||||||
//!
|
|
||||||
//! Having this pointer is useful because it allows state be moved out of global
|
|
||||||
//! variables into the kernel::Context struct before all global references to
|
|
||||||
//! that state are removed. This allows the global references to be removed
|
|
||||||
//! incrementally, instead of all at once.
|
|
||||||
extern Context* g_context;
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
|
|
||||||
#endif // BITCOIN_KERNEL_CONTEXT_H
|
#endif // BITCOIN_KERNEL_CONTEXT_H
|
||||||
|
|
|
@ -39,13 +39,13 @@
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <rpc/protocol.h>
|
#include <rpc/protocol.h>
|
||||||
#include <rpc/server.h>
|
#include <rpc/server.h>
|
||||||
#include <shutdown.h>
|
|
||||||
#include <support/allocators/secure.h>
|
#include <support/allocators/secure.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
#include <util/check.h>
|
#include <util/check.h>
|
||||||
|
#include <util/signalinterrupt.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
#include <validationinterface.h>
|
#include <validationinterface.h>
|
||||||
|
@ -99,7 +99,6 @@ public:
|
||||||
if (!AppInitParameterInteraction(args())) return false;
|
if (!AppInitParameterInteraction(args())) return false;
|
||||||
|
|
||||||
m_context->kernel = std::make_unique<kernel::Context>();
|
m_context->kernel = std::make_unique<kernel::Context>();
|
||||||
m_context->shutdown = &m_context->kernel->interrupt; // TEMPORARY: will go away when kernel->interrupt member is removed
|
|
||||||
if (!AppInitSanityChecks(*m_context->kernel)) return false;
|
if (!AppInitSanityChecks(*m_context->kernel)) return false;
|
||||||
|
|
||||||
if (!AppInitLockDataDirectory()) return false;
|
if (!AppInitLockDataDirectory()) return false;
|
||||||
|
@ -121,14 +120,16 @@ public:
|
||||||
}
|
}
|
||||||
void startShutdown() override
|
void startShutdown() override
|
||||||
{
|
{
|
||||||
StartShutdown();
|
if (!(*Assert(Assert(m_context)->shutdown))()) {
|
||||||
|
LogPrintf("Error: failed to send shutdown signal\n");
|
||||||
|
}
|
||||||
// Stop RPC for clean shutdown if any of waitfor* commands is executed.
|
// Stop RPC for clean shutdown if any of waitfor* commands is executed.
|
||||||
if (args().GetBoolArg("-server", false)) {
|
if (args().GetBoolArg("-server", false)) {
|
||||||
InterruptRPC();
|
InterruptRPC();
|
||||||
StopRPC();
|
StopRPC();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool shutdownRequested() override { return ShutdownRequested(); }
|
bool shutdownRequested() override { return ShutdownRequested(*Assert(m_context)); };
|
||||||
bool isSettingIgnored(const std::string& name) override
|
bool isSettingIgnored(const std::string& name) override
|
||||||
{
|
{
|
||||||
bool ignored = false;
|
bool ignored = false;
|
||||||
|
@ -750,7 +751,7 @@ public:
|
||||||
{
|
{
|
||||||
return chainman().IsInitialBlockDownload();
|
return chainman().IsInitialBlockDownload();
|
||||||
}
|
}
|
||||||
bool shutdownRequested() override { return ShutdownRequested(); }
|
bool shutdownRequested() override { return ShutdownRequested(m_node); }
|
||||||
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
|
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
|
||||||
void initWarning(const bilingual_str& message) override { InitWarning(message); }
|
void initWarning(const bilingual_str& message) override { InitWarning(message); }
|
||||||
void initError(const bilingual_str& message) override { InitError(message); }
|
void initError(const bilingual_str& message) override { InitError(message); }
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
||||||
// Copyright (c) 2009-2022 The Bitcoin Core developers
|
|
||||||
// Distributed under the MIT software license, see the accompanying
|
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
||||||
|
|
||||||
#include <shutdown.h>
|
|
||||||
|
|
||||||
#include <kernel/context.h>
|
|
||||||
#include <logging.h>
|
|
||||||
#include <util/check.h>
|
|
||||||
#include <util/signalinterrupt.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <system_error>
|
|
||||||
|
|
||||||
void StartShutdown()
|
|
||||||
{
|
|
||||||
if (!Assert(kernel::g_context)->interrupt()) {
|
|
||||||
LogPrintf("Sending shutdown token failed\n");
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AbortShutdown()
|
|
||||||
{
|
|
||||||
if (!Assert(kernel::g_context)->interrupt.reset()) {
|
|
||||||
LogPrintf("Reading shutdown token failed\n");
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ShutdownRequested()
|
|
||||||
{
|
|
||||||
return bool{Assert(kernel::g_context)->interrupt};
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitForShutdown()
|
|
||||||
{
|
|
||||||
if (!Assert(kernel::g_context)->interrupt.wait()) {
|
|
||||||
LogPrintf("Reading shutdown token failed\n");
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
||||||
// Copyright (c) 2009-2021 The Bitcoin Core developers
|
|
||||||
// Distributed under the MIT software license, see the accompanying
|
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
||||||
|
|
||||||
#ifndef BITCOIN_SHUTDOWN_H
|
|
||||||
#define BITCOIN_SHUTDOWN_H
|
|
||||||
|
|
||||||
/** Request shutdown of the application. */
|
|
||||||
void StartShutdown();
|
|
||||||
|
|
||||||
/** Clear shutdown flag. Only use this during init (before calling WaitForShutdown in any
|
|
||||||
* thread), or in the unit tests. Calling it in other circumstances will cause a race condition.
|
|
||||||
*/
|
|
||||||
void AbortShutdown();
|
|
||||||
|
|
||||||
/** Returns true if a shutdown is requested, false otherwise. */
|
|
||||||
bool ShutdownRequested();
|
|
||||||
|
|
||||||
/** Wait for StartShutdown to be called in any thread. This can only be used
|
|
||||||
* from a single thread.
|
|
||||||
*/
|
|
||||||
void WaitForShutdown();
|
|
||||||
|
|
||||||
#endif // BITCOIN_SHUTDOWN_H
|
|
|
@ -40,7 +40,6 @@
|
||||||
#include <rpc/server.h>
|
#include <rpc/server.h>
|
||||||
#include <scheduler.h>
|
#include <scheduler.h>
|
||||||
#include <script/sigcache.h>
|
#include <script/sigcache.h>
|
||||||
#include <shutdown.h>
|
|
||||||
#include <streams.h>
|
#include <streams.h>
|
||||||
#include <test/util/net.h>
|
#include <test/util/net.h>
|
||||||
#include <test/util/random.h>
|
#include <test/util/random.h>
|
||||||
|
|
Loading…
Add table
Reference in a new issue