Skip to content

Commit 5ca28ef

Browse files
ryanofskyMarcoFalke
authored and
MarcoFalke
committed
refactor: Split up NodeContext shutdown_signal and shutdown_request
Instead of having a single NodeContext::shutdown member that is used both to request shutdowns and check if they have been requested, use separate members for each. Benefits of this change: 1. Should make code a little clearer and easier to search because it is easier to see which parts of code are triggering shutdowns and which parts are just checking to see if they were triggered. 2. Makes it possible for init.cpp to specify additional code to run when a shutdown is requested, like signalling the m_tip_block_cv condition variable. Motivation for this change was to remove hacky NodeContext argument and m_tip_block_cv access from the StopRPC function, so StopRPC can just be concerned with RPC functionality, not other node functionality.
1 parent fad8e7f commit 5ca28ef

17 files changed

+53
-51
lines changed

src/bitcoind.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ MAIN_FUNCTION
274274
if (ProcessInitCommands(args)) return EXIT_SUCCESS;
275275

276276
// Start application
277-
if (!AppInit(node) || !Assert(node.shutdown)->wait()) {
277+
if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) {
278278
node.exit_status = EXIT_FAILURE;
279279
}
280280
Interrupt(node);

src/index/base.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ template <typename... Args>
3131
void BaseIndex::FatalErrorf(util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args)
3232
{
3333
auto message = tfm::format(fmt, args...);
34-
node::AbortNode(m_chain->context()->shutdown, m_chain->context()->exit_status, Untranslated(message), m_chain->context()->warnings.get());
34+
node::AbortNode(m_chain->context()->shutdown_request, m_chain->context()->exit_status, Untranslated(message), m_chain->context()->warnings.get());
3535
}
3636

3737
CBlockLocator GetLocator(interfaces::Chain& chain, const uint256& block_hash)

src/init.cpp

+16-9
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,14 @@ void InitContext(NodeContext& node)
207207
g_shutdown.emplace();
208208

209209
node.args = &gArgs;
210-
node.shutdown = &*g_shutdown;
210+
node.shutdown_signal = &*g_shutdown;
211+
node.shutdown_request = [&node] {
212+
assert(node.shutdown_signal);
213+
if (!(*node.shutdown_signal)()) return false;
214+
// Wake any threads that may be waiting for the tip to change.
215+
if (node.notifications) WITH_LOCK(node.notifications->m_tip_block_mutex, node.notifications->m_tip_block_cv.notify_all());
216+
return true;
217+
};
211218
}
212219

213220
//////////////////////////////////////////////////////////////////////////////
@@ -235,7 +242,7 @@ void InitContext(NodeContext& node)
235242

236243
bool ShutdownRequested(node::NodeContext& node)
237244
{
238-
return bool{*Assert(node.shutdown)};
245+
return bool{*Assert(node.shutdown_signal)};
239246
}
240247

241248
#if HAVE_SYSTEM
@@ -286,7 +293,7 @@ void Shutdown(NodeContext& node)
286293

287294
StopHTTPRPC();
288295
StopREST();
289-
StopRPC(&node);
296+
StopRPC();
290297
StopHTTPServer();
291298
for (const auto& client : node.chain_clients) {
292299
client->flush();
@@ -707,7 +714,7 @@ static void StartupNotify(const ArgsManager& args)
707714
static bool AppInitServers(NodeContext& node)
708715
{
709716
const ArgsManager& args = *Assert(node.args);
710-
if (!InitHTTPServer(*Assert(node.shutdown))) {
717+
if (!InitHTTPServer(*Assert(node.shutdown_signal))) {
711718
return false;
712719
}
713720
StartRPC();
@@ -1216,7 +1223,7 @@ static ChainstateLoadResult InitAndLoadChainstate(
12161223
};
12171224
Assert(ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction
12181225
try {
1219-
node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown), chainman_opts, blockman_opts);
1226+
node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown_signal), chainman_opts, blockman_opts);
12201227
} catch (std::exception& e) {
12211228
return {ChainstateLoadStatus::FAILURE_FATAL, strprintf(Untranslated("Failed to initialize ChainstateManager: %s"), e.what())};
12221229
}
@@ -1327,7 +1334,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
13271334
constexpr uint64_t min_disk_space = 50 << 20; // 50 MB
13281335
if (!CheckDiskSpace(args.GetBlocksDirPath(), min_disk_space)) {
13291336
LogError("Shutting down due to lack of disk space!\n");
1330-
if (!(*Assert(node.shutdown))()) {
1337+
if (!(Assert(node.shutdown_request))()) {
13311338
LogError("Failed to send shutdown signal after disk space check\n");
13321339
}
13331340
}
@@ -1608,7 +1615,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
16081615

16091616
// ********************************************************* Step 7: load block chain
16101617

1611-
node.notifications = std::make_unique<KernelNotifications>(*Assert(node.shutdown), node.exit_status, *Assert(node.warnings));
1618+
node.notifications = std::make_unique<KernelNotifications>(Assert(node.shutdown_request), node.exit_status, *Assert(node.warnings));
16121619
ReadNotificationArgs(args, *node.notifications);
16131620

16141621
// cache size calculations
@@ -1649,7 +1656,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
16491656
return false;
16501657
}
16511658
do_reindex = true;
1652-
if (!Assert(node.shutdown)->reset()) {
1659+
if (!Assert(node.shutdown_signal)->reset()) {
16531660
LogError("Internal error: failed to reset shutdown signal.\n");
16541661
}
16551662
std::tie(status, error) = InitAndLoadChainstate(
@@ -1794,7 +1801,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
17941801
ImportBlocks(chainman, vImportFiles);
17951802
if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
17961803
LogPrintf("Stopping after block import\n");
1797-
if (!(*Assert(node.shutdown))()) {
1804+
if (!(Assert(node.shutdown_request))()) {
17981805
LogError("Failed to send shutdown signal after finishing block import\n");
17991806
}
18001807
return;

src/node/abort.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515

1616
namespace node {
1717

18-
void AbortNode(util::SignalInterrupt* shutdown, std::atomic<int>& exit_status, const bilingual_str& message, node::Warnings* warnings)
18+
void AbortNode(const std::function<bool()>& shutdown_request, std::atomic<int>& exit_status, const bilingual_str& message, node::Warnings* warnings)
1919
{
2020
if (warnings) warnings->Set(Warning::FATAL_INTERNAL_ERROR, message);
2121
InitError(_("A fatal internal error occurred, see debug.log for details: ") + message);
2222
exit_status.store(EXIT_FAILURE);
23-
if (shutdown && !(*shutdown)()) {
23+
if (shutdown_request && !shutdown_request()) {
2424
LogError("Failed to send shutdown signal\n");
2525
};
2626
}

src/node/abort.h

+2-5
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,13 @@
66
#define BITCOIN_NODE_ABORT_H
77

88
#include <atomic>
9+
#include <functional>
910

1011
struct bilingual_str;
1112

12-
namespace util {
13-
class SignalInterrupt;
14-
} // namespace util
15-
1613
namespace node {
1714
class Warnings;
18-
void AbortNode(util::SignalInterrupt* shutdown, std::atomic<int>& exit_status, const bilingual_str& message, node::Warnings* warnings);
15+
void AbortNode(const std::function<bool()>& shutdown_request, std::atomic<int>& exit_status, const bilingual_str& message, node::Warnings* warnings);
1916
} // namespace node
2017

2118
#endif // BITCOIN_NODE_ABORT_H

src/node/context.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ struct NodeContext {
5959
std::unique_ptr<ECC_Context> ecc_context;
6060
//! Init interface for initializing current process and connecting to other processes.
6161
interfaces::Init* init{nullptr};
62+
//! Function to request a shutdown.
63+
std::function<bool()> shutdown_request;
6264
//! Interrupt object used to track whether node shutdown was requested.
63-
util::SignalInterrupt* shutdown{nullptr};
65+
util::SignalInterrupt* shutdown_signal{nullptr};
6466
std::unique_ptr<AddrMan> addrman;
6567
std::unique_ptr<CConnman> connman;
6668
std::unique_ptr<CTxMemPool> mempool;

src/node/interfaces.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,15 @@ class NodeImpl : public Node
134134
}
135135
void startShutdown() override
136136
{
137-
if (!(*Assert(Assert(m_context)->shutdown))()) {
137+
NodeContext& ctx{*Assert(m_context)};
138+
if (!(Assert(ctx.shutdown_request))()) {
138139
LogError("Failed to send shutdown signal\n");
139140
}
141+
140142
// Stop RPC for clean shutdown if any of waitfor* commands is executed.
141143
if (args().GetBoolArg("-server", false)) {
142144
InterruptRPC();
143-
StopRPC(m_context);
145+
StopRPC();
144146
}
145147
}
146148
bool shutdownRequested() override { return ShutdownRequested(*Assert(m_context)); };

src/node/kernel_notifications.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ kernel::InterruptResult KernelNotifications::blockTip(SynchronizationState state
5858

5959
uiInterface.NotifyBlockTip(state, &index);
6060
if (m_stop_at_height && index.nHeight >= m_stop_at_height) {
61-
if (!m_shutdown()) {
61+
if (!m_shutdown_request()) {
6262
LogError("Failed to send shutdown signal after reaching stop height\n");
6363
}
6464
return kernel::Interrupted{};
@@ -90,12 +90,12 @@ void KernelNotifications::warningUnset(kernel::Warning id)
9090

9191
void KernelNotifications::flushError(const bilingual_str& message)
9292
{
93-
AbortNode(&m_shutdown, m_exit_status, message, &m_warnings);
93+
AbortNode(m_shutdown_request, m_exit_status, message, &m_warnings);
9494
}
9595

9696
void KernelNotifications::fatalError(const bilingual_str& message)
9797
{
98-
node::AbortNode(m_shutdown_on_fatal_error ? &m_shutdown : nullptr,
98+
node::AbortNode(m_shutdown_on_fatal_error ? m_shutdown_request : nullptr,
9999
m_exit_status, message, &m_warnings);
100100
}
101101

src/node/kernel_notifications.h

+4-7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <atomic>
1515
#include <cstdint>
16+
#include <functional>
1617

1718
class ArgsManager;
1819
class CBlockIndex;
@@ -23,10 +24,6 @@ namespace kernel {
2324
enum class Warning;
2425
} // namespace kernel
2526

26-
namespace util {
27-
class SignalInterrupt;
28-
} // namespace util
29-
3027
namespace node {
3128

3229
class Warnings;
@@ -35,8 +32,8 @@ static constexpr int DEFAULT_STOPATHEIGHT{0};
3532
class KernelNotifications : public kernel::Notifications
3633
{
3734
public:
38-
KernelNotifications(util::SignalInterrupt& shutdown, std::atomic<int>& exit_status, node::Warnings& warnings)
39-
: m_shutdown(shutdown), m_exit_status{exit_status}, m_warnings{warnings} {}
35+
KernelNotifications(const std::function<bool()>& shutdown_request, std::atomic<int>& exit_status, node::Warnings& warnings)
36+
: m_shutdown_request(shutdown_request), m_exit_status{exit_status}, m_warnings{warnings} {}
4037

4138
[[nodiscard]] kernel::InterruptResult blockTip(SynchronizationState state, CBlockIndex& index) override EXCLUSIVE_LOCKS_REQUIRED(!m_tip_block_mutex);
4239

@@ -63,7 +60,7 @@ class KernelNotifications : public kernel::Notifications
6360
uint256 m_tip_block GUARDED_BY(m_tip_block_mutex);
6461

6562
private:
66-
util::SignalInterrupt& m_shutdown;
63+
const std::function<bool()>& m_shutdown_request;
6764
std::atomic<int>& m_exit_status;
6865
node::Warnings& m_warnings;
6966
};

src/rpc/server.cpp

+2-5
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ static RPCHelpMan stop()
169169
{
170170
// Event loop will exit after current HTTP requests have been handled, so
171171
// this reply will get back to the client.
172-
CHECK_NONFATAL((*CHECK_NONFATAL(EnsureAnyNodeContext(jsonRequest.context).shutdown))());
172+
CHECK_NONFATAL((CHECK_NONFATAL(EnsureAnyNodeContext(jsonRequest.context).shutdown_request))());
173173
if (jsonRequest.params[0].isNum()) {
174174
UninterruptibleSleep(std::chrono::milliseconds{jsonRequest.params[0].getInt<int>()});
175175
}
@@ -294,7 +294,7 @@ void InterruptRPC()
294294
});
295295
}
296296

297-
void StopRPC(const std::any& context)
297+
void StopRPC()
298298
{
299299
static std::once_flag g_rpc_stop_flag;
300300
// This function could be called twice if the GUI has been started with -server=1.
@@ -303,9 +303,6 @@ void StopRPC(const std::any& context)
303303
LogDebug(BCLog::RPC, "Stopping RPC\n");
304304
WITH_LOCK(g_deadline_timers_mutex, deadlineTimers.clear());
305305
DeleteAuthCookie();
306-
node::NodeContext& node = EnsureAnyNodeContext(context);
307-
// The notifications interface doesn't exist between initialization step 4a and 7.
308-
if (node.notifications) WITH_LOCK(node.notifications->m_tip_block_mutex, node.notifications->m_tip_block_cv.notify_all());
309306
LogDebug(BCLog::RPC, "RPC stopped.\n");
310307
});
311308
}

src/rpc/server.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include <rpc/request.h>
1010
#include <rpc/util.h>
1111

12-
#include <any>
1312
#include <functional>
1413
#include <map>
1514
#include <stdint.h>
@@ -173,7 +172,7 @@ extern CRPCTable tableRPC;
173172

174173
void StartRPC();
175174
void InterruptRPC();
176-
void StopRPC(const std::any& context);
175+
void StopRPC();
177176
UniValue JSONRPCExec(const JSONRPCRequest& jreq, bool catch_errors);
178177

179178
#endif // BITCOIN_RPC_SERVER_H

src/test/blockfilter_index_tests.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
144144
BOOST_REQUIRE(filter_index.StartBackgroundSync());
145145

146146
// Allow filter index to catch up with the block index.
147-
IndexWaitSynced(filter_index, *Assert(m_node.shutdown));
147+
IndexWaitSynced(filter_index, *Assert(m_node.shutdown_signal));
148148

149149
// Check that filter index has all blocks that were in the chain before it started.
150150
{

src/test/blockmanager_tests.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@ BOOST_FIXTURE_TEST_SUITE(blockmanager_tests, BasicTestingSetup)
2828
BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
2929
{
3030
const auto params {CreateChainParams(ArgsManager{}, ChainType::MAIN)};
31-
KernelNotifications notifications{*Assert(m_node.shutdown), m_node.exit_status, *Assert(m_node.warnings)};
31+
KernelNotifications notifications{Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings)};
3232
const BlockManager::Options blockman_opts{
3333
.chainparams = *params,
3434
.blocks_dir = m_args.GetBlocksDirPath(),
3535
.notifications = notifications,
3636
};
37-
BlockManager blockman{*Assert(m_node.shutdown), blockman_opts};
37+
BlockManager blockman{*Assert(m_node.shutdown_signal), blockman_opts};
3838
// simulate adding a genesis block normally
3939
BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0).nPos, BLOCK_SERIALIZATION_HEADER_SIZE);
4040
// simulate what happens during reindex
@@ -135,13 +135,13 @@ BOOST_FIXTURE_TEST_CASE(blockmanager_block_data_availability, TestChain100Setup)
135135

136136
BOOST_AUTO_TEST_CASE(blockmanager_flush_block_file)
137137
{
138-
KernelNotifications notifications{*Assert(m_node.shutdown), m_node.exit_status, *Assert(m_node.warnings)};
138+
KernelNotifications notifications{Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings)};
139139
node::BlockManager::Options blockman_opts{
140140
.chainparams = Params(),
141141
.blocks_dir = m_args.GetBlocksDirPath(),
142142
.notifications = notifications,
143143
};
144-
BlockManager blockman{*Assert(m_node.shutdown), blockman_opts};
144+
BlockManager blockman{*Assert(m_node.shutdown_signal), blockman_opts};
145145

146146
// Test blocks with no transactions, not even a coinbase
147147
CBlock block1;

src/test/coinstatsindex_tests.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
3535

3636
BOOST_REQUIRE(coin_stats_index.StartBackgroundSync());
3737

38-
IndexWaitSynced(coin_stats_index, *Assert(m_node.shutdown));
38+
IndexWaitSynced(coin_stats_index, *Assert(m_node.shutdown_signal));
3939

4040
// Check that CoinStatsIndex works for genesis block.
4141
const CBlockIndex* genesis_block_index;
@@ -86,7 +86,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
8686
CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
8787
BOOST_REQUIRE(index.Init());
8888
BOOST_REQUIRE(index.StartBackgroundSync());
89-
IndexWaitSynced(index, *Assert(m_node.shutdown));
89+
IndexWaitSynced(index, *Assert(m_node.shutdown_signal));
9090
std::shared_ptr<const CBlock> new_block;
9191
CBlockIndex* new_block_index = nullptr;
9292
{

src/test/txindex_tests.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
3333
BOOST_REQUIRE(txindex.StartBackgroundSync());
3434

3535
// Allow tx index to catch up with the block index.
36-
IndexWaitSynced(txindex, *Assert(m_node.shutdown));
36+
IndexWaitSynced(txindex, *Assert(m_node.shutdown_signal));
3737

3838
// Check that txindex excludes genesis block transactions.
3939
const CBlock& genesis_block = Params().GenesisBlock();

src/test/util/setup_common.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ static void ExitFailure(std::string_view str_err)
104104
BasicTestingSetup::BasicTestingSetup(const ChainType chainType, TestOpts opts)
105105
: m_args{}
106106
{
107-
m_node.shutdown = &m_interrupt;
107+
m_node.shutdown_signal = &m_interrupt;
108+
m_node.shutdown_request = [this]{ return m_interrupt(); };
108109
m_node.args = &gArgs;
109110
std::vector<const char*> arguments = Cat(
110111
{
@@ -224,7 +225,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts)
224225

225226
m_cache_sizes = CalculateCacheSizes(m_args);
226227

227-
m_node.notifications = std::make_unique<KernelNotifications>(*Assert(m_node.shutdown), m_node.exit_status, *Assert(m_node.warnings));
228+
m_node.notifications = std::make_unique<KernelNotifications>(Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings));
228229

229230
m_make_chainman = [this, &chainparams, opts] {
230231
Assert(!m_node.chainman);
@@ -245,7 +246,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts)
245246
.blocks_dir = m_args.GetBlocksDirPath(),
246247
.notifications = chainman_opts.notifications,
247248
};
248-
m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown), chainman_opts, blockman_opts);
249+
m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown_signal), chainman_opts, blockman_opts);
249250
LOCK(m_node.chainman->GetMutex());
250251
m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<BlockTreeDB>(DBParams{
251252
.path = m_args.GetDataDirNet() / "blocks" / "index",

src/test/validation_chainstatemanager_tests.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ struct SnapshotTestSetup : TestChain100Setup {
382382
LOCK(::cs_main);
383383
chainman.ResetChainstates();
384384
BOOST_CHECK_EQUAL(chainman.GetAll().size(), 0);
385-
m_node.notifications = std::make_unique<KernelNotifications>(*Assert(m_node.shutdown), m_node.exit_status, *Assert(m_node.warnings));
385+
m_node.notifications = std::make_unique<KernelNotifications>(Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings));
386386
const ChainstateManager::Options chainman_opts{
387387
.chainparams = ::Params(),
388388
.datadir = chainman.m_options.datadir,
@@ -397,7 +397,7 @@ struct SnapshotTestSetup : TestChain100Setup {
397397
// For robustness, ensure the old manager is destroyed before creating a
398398
// new one.
399399
m_node.chainman.reset();
400-
m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown), chainman_opts, blockman_opts);
400+
m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown_signal), chainman_opts, blockman_opts);
401401
}
402402
return *Assert(m_node.chainman);
403403
}

0 commit comments

Comments
 (0)