Skip to content

Commit 6db04be

Browse files
committed
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 bitcoin#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.
1 parent 213542b commit 6db04be

File tree

10 files changed

+47
-121
lines changed

10 files changed

+47
-121
lines changed

src/Makefile.am

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,6 @@ BITCOIN_CORE_H = \
271271
script/sign.h \
272272
script/signingprovider.h \
273273
script/solver.h \
274-
shutdown.h \
275274
signet.h \
276275
streams.h \
277276
support/allocators/pool.h \
@@ -459,7 +458,6 @@ libbitcoin_node_a_SOURCES = \
459458
rpc/signmessage.cpp \
460459
rpc/txoutproof.cpp \
461460
script/sigcache.cpp \
462-
shutdown.cpp \
463461
signet.cpp \
464462
timedata.cpp \
465463
torcontrol.cpp \

src/bitcoind.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
#include <node/context.h>
2121
#include <node/interface_ui.h>
2222
#include <noui.h>
23-
#include <shutdown.h>
2423
#include <util/check.h>
2524
#include <util/exception.h>
2625
#include <util/strencodings.h>
@@ -185,7 +184,6 @@ static bool AppInit(NodeContext& node)
185184
}
186185

187186
node.kernel = std::make_unique<kernel::Context>();
188-
node.shutdown = &node.kernel->interrupt; // TEMPORARY: will go away when kernel->interrupt member is removed
189187
if (!AppInitSanityChecks(*node.kernel))
190188
{
191189
// InitError will have been called with detailed error, which ends up on console
@@ -273,9 +271,7 @@ MAIN_FUNCTION
273271
if (ProcessInitCommands(args)) return EXIT_SUCCESS;
274272

275273
// Start application
276-
if (AppInit(node)) {
277-
WaitForShutdown();
278-
} else {
274+
if (!AppInit(node) || !Assert(node.shutdown)->wait()) {
279275
node.exit_status = EXIT_FAILURE;
280276
}
281277
Interrupt(node);

src/init.cpp

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
#include <rpc/util.h>
6767
#include <scheduler.h>
6868
#include <script/sigcache.h>
69-
#include <shutdown.h>
7069
#include <sync.h>
7170
#include <timedata.h>
7271
#include <torcontrol.h>
@@ -192,9 +191,15 @@ static void RemovePidFile(const ArgsManager& args)
192191
}
193192
}
194193

194+
static std::optional<util::SignalInterrupt> g_shutdown;
195+
195196
void InitContext(NodeContext& node)
196197
{
198+
assert(!g_shutdown);
199+
g_shutdown.emplace();
200+
197201
node.args = &gArgs;
202+
node.shutdown = &*g_shutdown;
198203
}
199204

200205
//////////////////////////////////////////////////////////////////////////////
@@ -208,11 +213,9 @@ void InitContext(NodeContext& node)
208213
// The network-processing threads are all part of a thread group
209214
// created by AppInit() or the Qt main() function.
210215
//
211-
// A clean exit happens when StartShutdown() or the SIGTERM
212-
// signal handler sets ShutdownRequested(), which makes main thread's
213-
// WaitForShutdown() interrupts the thread group.
214-
// And then, WaitForShutdown() makes all other on-going threads
215-
// in the thread group join the main thread.
216+
// A clean exit happens when the SignalInterrupt object is triggered, which
217+
// makes the main thread's SignalInterrupt::wait() call return, and join all
218+
// other ongoing threads in the thread group to the main thread.
216219
// Shutdown() is then called to clean up database connections, and stop other
217220
// threads that should only be stopped after the main network-processing
218221
// threads have exited.
@@ -222,6 +225,11 @@ void InitContext(NodeContext& node)
222225
// shutdown thing.
223226
//
224227

228+
bool ShutdownRequested(node::NodeContext& node)
229+
{
230+
return bool{*Assert(node.shutdown)};
231+
}
232+
225233
#if HAVE_SYSTEM
226234
static void ShutdownNotify(const ArgsManager& args)
227235
{
@@ -386,7 +394,9 @@ void Shutdown(NodeContext& node)
386394
#ifndef WIN32
387395
static void HandleSIGTERM(int)
388396
{
389-
StartShutdown();
397+
// Return value is intentionally ignored because there is not a better way
398+
// of handling this failure in a signal handler.
399+
(void)(*Assert(g_shutdown))();
390400
}
391401

392402
static void HandleSIGHUP(int)
@@ -396,7 +406,10 @@ static void HandleSIGHUP(int)
396406
#else
397407
static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType)
398408
{
399-
StartShutdown();
409+
if (!(*Assert(g_shutdown))()) {
410+
LogPrintf("Error: failed to send shutdown signal on Ctrl-C\n");
411+
return false;
412+
}
400413
Sleep(INFINITE);
401414
return true;
402415
}
@@ -1145,11 +1158,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
11451158
}, std::chrono::minutes{1});
11461159

11471160
// Check disk space every 5 minutes to avoid db corruption.
1148-
node.scheduler->scheduleEvery([&args]{
1161+
node.scheduler->scheduleEvery([&args, &node]{
11491162
constexpr uint64_t min_disk_space = 50 << 20; // 50 MB
11501163
if (!CheckDiskSpace(args.GetBlocksDirPath(), min_disk_space)) {
11511164
LogPrintf("Shutting down due to lack of disk space!\n");
1152-
StartShutdown();
1165+
if (!(*Assert(node.shutdown))()) {
1166+
LogPrintf("Error: failed to send shutdown signal after disk space check\n");
1167+
}
11531168
}
11541169
}, std::chrono::minutes{5});
11551170

@@ -1487,7 +1502,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
14871502
}
14881503
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));
14891504

1490-
for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) {
1505+
for (bool fLoaded = false; !fLoaded && !ShutdownRequested(node);) {
14911506
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
14921507

14931508
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)
15541569
return InitError(error);
15551570
}
15561571

1557-
if (!fLoaded && !ShutdownRequested()) {
1572+
if (!fLoaded && !ShutdownRequested(node)) {
15581573
// first suggest a reindex
15591574
if (!options.reindex) {
15601575
bool fRet = uiInterface.ThreadSafeQuestion(
@@ -1563,7 +1578,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
15631578
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
15641579
if (fRet) {
15651580
fReindex = true;
1566-
AbortShutdown();
1581+
if (!Assert(node.shutdown)->reset()) {
1582+
LogPrintf("Internal error: failed to reset shutdown signal.\n");
1583+
}
15671584
} else {
15681585
LogPrintf("Aborted block database rebuild. Exiting.\n");
15691586
return false;
@@ -1577,7 +1594,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
15771594
// As LoadBlockIndex can take several minutes, it's possible the user
15781595
// requested to kill the GUI during the last operation. If so, exit.
15791596
// As the program has not fully started yet, Shutdown() is possibly overkill.
1580-
if (ShutdownRequested()) {
1597+
if (ShutdownRequested(node)) {
15811598
LogPrintf("Shutdown requested. Exiting.\n");
15821599
return false;
15831600
}
@@ -1698,7 +1715,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
16981715
ImportBlocks(chainman, vImportFiles);
16991716
if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) {
17001717
LogPrintf("Stopping after block import\n");
1701-
StartShutdown();
1718+
if (!(*Assert(node.shutdown))()) {
1719+
LogPrintf("Error: failed to send shutdown signal after finishing block import\n");
1720+
}
17021721
return;
17031722
}
17041723

@@ -1718,16 +1737,16 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
17181737
// Wait for genesis block to be processed
17191738
{
17201739
WAIT_LOCK(g_genesis_wait_mutex, lock);
1721-
// We previously could hang here if StartShutdown() is called prior to
1740+
// We previously could hang here if shutdown was requested prior to
17221741
// ImportBlocks getting started, so instead we just wait on a timer to
17231742
// check ShutdownRequested() regularly.
1724-
while (!fHaveGenesis && !ShutdownRequested()) {
1743+
while (!fHaveGenesis && !ShutdownRequested(node)) {
17251744
g_genesis_wait_cv.wait_for(lock, std::chrono::milliseconds(500));
17261745
}
17271746
block_notify_genesis_wait_connection.disconnect();
17281747
}
17291748

1730-
if (ShutdownRequested()) {
1749+
if (ShutdownRequested(node)) {
17311750
return false;
17321751
}
17331752

src/init.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@ namespace node {
2626
struct NodeContext;
2727
} // namespace node
2828

29-
/** Initialize node context variables. */
29+
/** Initialize node context shutdown and args variables. */
3030
void InitContext(node::NodeContext& node);
31+
/** Return whether node shutdown was requested. */
32+
bool ShutdownRequested(node::NodeContext& node);
3133

3234
/** Interrupt threads */
3335
void Interrupt(node::NodeContext& node);

src/kernel/context.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,8 @@
1414

1515

1616
namespace kernel {
17-
Context* g_context;
18-
1917
Context::Context()
2018
{
21-
assert(!g_context);
22-
g_context = this;
2319
std::string sha256_algo = SHA256AutoDetect();
2420
LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo);
2521
RandomInit();
@@ -29,8 +25,6 @@ Context::Context()
2925
Context::~Context()
3026
{
3127
ECC_Stop();
32-
assert(g_context);
33-
g_context = nullptr;
3428
}
3529

3630
} // namespace kernel

src/kernel/context.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,9 @@ namespace kernel {
1818
//! State stored directly in this struct should be simple. More complex state
1919
//! should be stored to std::unique_ptr members pointing to opaque types.
2020
struct Context {
21-
//! Interrupt object that can be used to stop long-running kernel operations.
22-
util::SignalInterrupt interrupt;
23-
24-
//! Declare default constructor and destructor that are not inline, so code
25-
//! instantiating the kernel::Context struct doesn't need to #include class
26-
//! definitions for all the unique_ptr members.
2721
Context();
2822
~Context();
2923
};
30-
31-
//! Global pointer to kernel::Context for legacy code. New code should avoid
32-
//! using this, and require state it needs to be passed to it directly.
33-
//!
34-
//! Having this pointer is useful because it allows state be moved out of global
35-
//! variables into the kernel::Context struct before all global references to
36-
//! that state are removed. This allows the global references to be removed
37-
//! incrementally, instead of all at once.
38-
extern Context* g_context;
3924
} // namespace kernel
4025

4126
#endif // BITCOIN_KERNEL_CONTEXT_H

src/node/interfaces.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@
3939
#include <primitives/transaction.h>
4040
#include <rpc/protocol.h>
4141
#include <rpc/server.h>
42-
#include <shutdown.h>
4342
#include <support/allocators/secure.h>
4443
#include <sync.h>
4544
#include <txmempool.h>
4645
#include <uint256.h>
4746
#include <univalue.h>
4847
#include <util/check.h>
48+
#include <util/signalinterrupt.h>
4949
#include <util/translation.h>
5050
#include <validation.h>
5151
#include <validationinterface.h>
@@ -99,7 +99,6 @@ class NodeImpl : public Node
9999
if (!AppInitParameterInteraction(args())) return false;
100100

101101
m_context->kernel = std::make_unique<kernel::Context>();
102-
m_context->shutdown = &m_context->kernel->interrupt; // TEMPORARY: will go away when kernel->interrupt member is removed
103102
if (!AppInitSanityChecks(*m_context->kernel)) return false;
104103

105104
if (!AppInitLockDataDirectory()) return false;
@@ -121,14 +120,16 @@ class NodeImpl : public Node
121120
}
122121
void startShutdown() override
123122
{
124-
StartShutdown();
123+
if (!(*Assert(Assert(m_context)->shutdown))()) {
124+
LogPrintf("Error: failed to send shutdown signal\n");
125+
}
125126
// Stop RPC for clean shutdown if any of waitfor* commands is executed.
126127
if (args().GetBoolArg("-server", false)) {
127128
InterruptRPC();
128129
StopRPC();
129130
}
130131
}
131-
bool shutdownRequested() override { return ShutdownRequested(); }
132+
bool shutdownRequested() override { return ShutdownRequested(*Assert(m_context)); };
132133
bool isSettingIgnored(const std::string& name) override
133134
{
134135
bool ignored = false;
@@ -750,7 +751,7 @@ class ChainImpl : public Chain
750751
{
751752
return chainman().IsInitialBlockDownload();
752753
}
753-
bool shutdownRequested() override { return ShutdownRequested(); }
754+
bool shutdownRequested() override { return ShutdownRequested(m_node); }
754755
void initMessage(const std::string& message) override { ::uiInterface.InitMessage(message); }
755756
void initWarning(const bilingual_str& message) override { InitWarning(message); }
756757
void initError(const bilingual_str& message) override { InitError(message); }

src/shutdown.cpp

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/shutdown.h

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/test/util/setup_common.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
#include <rpc/server.h>
4141
#include <scheduler.h>
4242
#include <script/sigcache.h>
43-
#include <shutdown.h>
4443
#include <streams.h>
4544
#include <test/util/net.h>
4645
#include <test/util/random.h>

0 commit comments

Comments
 (0)