66
66
#include < rpc/util.h>
67
67
#include < scheduler.h>
68
68
#include < script/sigcache.h>
69
- #include < shutdown.h>
70
69
#include < sync.h>
71
70
#include < timedata.h>
72
71
#include < torcontrol.h>
@@ -192,9 +191,15 @@ static void RemovePidFile(const ArgsManager& args)
192
191
}
193
192
}
194
193
194
+ static std::optional<util::SignalInterrupt> g_shutdown;
195
+
195
196
void InitContext (NodeContext& node)
196
197
{
198
+ assert (!g_shutdown);
199
+ g_shutdown.emplace ();
200
+
197
201
node.args = &gArgs ;
202
+ node.shutdown = &*g_shutdown;
198
203
}
199
204
200
205
// ////////////////////////////////////////////////////////////////////////////
@@ -208,11 +213,9 @@ void InitContext(NodeContext& node)
208
213
// The network-processing threads are all part of a thread group
209
214
// created by AppInit() or the Qt main() function.
210
215
//
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.
216
219
// Shutdown() is then called to clean up database connections, and stop other
217
220
// threads that should only be stopped after the main network-processing
218
221
// threads have exited.
@@ -222,6 +225,11 @@ void InitContext(NodeContext& node)
222
225
// shutdown thing.
223
226
//
224
227
228
+ bool ShutdownRequested (node::NodeContext& node)
229
+ {
230
+ return bool {*Assert (node.shutdown )};
231
+ }
232
+
225
233
#if HAVE_SYSTEM
226
234
static void ShutdownNotify (const ArgsManager& args)
227
235
{
@@ -386,7 +394,9 @@ void Shutdown(NodeContext& node)
386
394
#ifndef WIN32
387
395
static void HandleSIGTERM (int )
388
396
{
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))();
390
400
}
391
401
392
402
static void HandleSIGHUP (int )
@@ -396,7 +406,10 @@ static void HandleSIGHUP(int)
396
406
#else
397
407
static BOOL WINAPI consoleCtrlHandler (DWORD dwCtrlType)
398
408
{
399
- StartShutdown ();
409
+ if (!(*Assert (g_shutdown))()) {
410
+ LogPrintf (" Error: failed to send shutdown signal on Ctrl-C\n " );
411
+ return false ;
412
+ }
400
413
Sleep (INFINITE);
401
414
return true ;
402
415
}
@@ -1145,11 +1158,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1145
1158
}, std::chrono::minutes{1 });
1146
1159
1147
1160
// Check disk space every 5 minutes to avoid db corruption.
1148
- node.scheduler ->scheduleEvery ([&args]{
1161
+ node.scheduler ->scheduleEvery ([&args, &node ]{
1149
1162
constexpr uint64_t min_disk_space = 50 << 20 ; // 50 MB
1150
1163
if (!CheckDiskSpace (args.GetBlocksDirPath (), min_disk_space)) {
1151
1164
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
+ }
1153
1168
}
1154
1169
}, std::chrono::minutes{5 });
1155
1170
@@ -1487,7 +1502,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1487
1502
}
1488
1503
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 ));
1489
1504
1490
- for (bool fLoaded = false ; !fLoaded && !ShutdownRequested ();) {
1505
+ for (bool fLoaded = false ; !fLoaded && !ShutdownRequested (node );) {
1491
1506
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
1492
1507
1493
1508
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)
1554
1569
return InitError (error);
1555
1570
}
1556
1571
1557
- if (!fLoaded && !ShutdownRequested ()) {
1572
+ if (!fLoaded && !ShutdownRequested (node )) {
1558
1573
// first suggest a reindex
1559
1574
if (!options.reindex ) {
1560
1575
bool fRet = uiInterface.ThreadSafeQuestion (
@@ -1563,7 +1578,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1563
1578
" " , CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
1564
1579
if (fRet ) {
1565
1580
fReindex = true ;
1566
- AbortShutdown ();
1581
+ if (!Assert (node.shutdown )->reset ()) {
1582
+ LogPrintf (" Internal error: failed to reset shutdown signal.\n " );
1583
+ }
1567
1584
} else {
1568
1585
LogPrintf (" Aborted block database rebuild. Exiting.\n " );
1569
1586
return false ;
@@ -1577,7 +1594,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1577
1594
// As LoadBlockIndex can take several minutes, it's possible the user
1578
1595
// requested to kill the GUI during the last operation. If so, exit.
1579
1596
// As the program has not fully started yet, Shutdown() is possibly overkill.
1580
- if (ShutdownRequested ()) {
1597
+ if (ShutdownRequested (node )) {
1581
1598
LogPrintf (" Shutdown requested. Exiting.\n " );
1582
1599
return false ;
1583
1600
}
@@ -1698,7 +1715,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1698
1715
ImportBlocks (chainman, vImportFiles);
1699
1716
if (args.GetBoolArg (" -stopafterblockimport" , DEFAULT_STOPAFTERBLOCKIMPORT)) {
1700
1717
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
+ }
1702
1721
return ;
1703
1722
}
1704
1723
@@ -1718,16 +1737,16 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1718
1737
// Wait for genesis block to be processed
1719
1738
{
1720
1739
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
1722
1741
// ImportBlocks getting started, so instead we just wait on a timer to
1723
1742
// check ShutdownRequested() regularly.
1724
- while (!fHaveGenesis && !ShutdownRequested ()) {
1743
+ while (!fHaveGenesis && !ShutdownRequested (node )) {
1725
1744
g_genesis_wait_cv.wait_for (lock, std::chrono::milliseconds (500 ));
1726
1745
}
1727
1746
block_notify_genesis_wait_connection.disconnect ();
1728
1747
}
1729
1748
1730
- if (ShutdownRequested ()) {
1749
+ if (ShutdownRequested (node )) {
1731
1750
return false ;
1732
1751
}
1733
1752
0 commit comments