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+
195196void 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
226234static void ShutdownNotify (const ArgsManager& args)
227235{
@@ -386,7 +394,9 @@ void Shutdown(NodeContext& node)
386394#ifndef WIN32
387395static 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
392402static void HandleSIGHUP (int )
@@ -396,7 +406,10 @@ static void HandleSIGHUP(int)
396406#else
397407static 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
0 commit comments