Skip to content

Commit 3192975

Browse files
committed
Flush CValidationInterface callbacks prior to destruction
Note that the CScheduler thread cant be running at this point, it has already been stopped with the rest of the init threadgroup. Thus, just calling any remaining loose callbacks during Shutdown() is sane.
1 parent 08096bb commit 3192975

File tree

6 files changed

+32
-0
lines changed

6 files changed

+32
-0
lines changed

src/init.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,19 @@ void Shutdown()
215215
fFeeEstimatesInitialized = false;
216216
}
217217

218+
// FlushStateToDisk generates a SetBestChain callback, which we should avoid missing
219+
FlushStateToDisk();
220+
221+
// After there are no more peers/RPC left to give us new data which may generate
222+
// CValidationInterface callbacks, flush them...
223+
GetMainSignals().FlushBackgroundCallbacks();
224+
225+
// Any future callbacks will be dropped. This should absolutely be safe - if
226+
// missing a callback results in an unrecoverable situation, unclean shutdown
227+
// would too. The only reason to do the above flushes is to let the wallet catch
228+
// up with our current chain to avoid any strange pruning edge cases and make
229+
// next startup faster by avoiding rescan.
230+
218231
{
219232
LOCK(cs_main);
220233
if (pcoinsTip != NULL) {

src/scheduler.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,12 @@ void SingleThreadedSchedulerClient::AddToProcessQueue(std::function<void (void)>
191191
}
192192
MaybeScheduleProcessQueue();
193193
}
194+
195+
void SingleThreadedSchedulerClient::EmptyQueue() {
196+
bool should_continue = true;
197+
while (should_continue) {
198+
ProcessQueue();
199+
LOCK(m_cs_callbacks_pending);
200+
should_continue = !m_callbacks_pending.empty();
201+
}
202+
}

src/scheduler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ class SingleThreadedSchedulerClient {
101101
public:
102102
SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {}
103103
void AddToProcessQueue(std::function<void (void)> func);
104+
105+
// Processes all remaining queue members on the calling thread, blocking until queue is empty
106+
void EmptyQueue();
104107
};
105108

106109
#endif

src/test/test_bitcoin.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ TestingSetup::~TestingSetup()
9494
UnregisterNodeSignals(GetNodeSignals());
9595
threadGroup.interrupt_all();
9696
threadGroup.join_all();
97+
GetMainSignals().FlushBackgroundCallbacks();
9798
GetMainSignals().UnregisterBackgroundSignalScheduler();
9899
UnloadBlockIndex();
99100
delete pcoinsTip;

src/validationinterface.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ void CMainSignals::UnregisterBackgroundSignalScheduler() {
4444
m_internals.reset(nullptr);
4545
}
4646

47+
void CMainSignals::FlushBackgroundCallbacks() {
48+
m_internals->m_schedulerClient.EmptyQueue();
49+
}
50+
4751
CMainSignals& GetMainSignals()
4852
{
4953
return g_signals;

src/validationinterface.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ class CMainSignals {
7979
void RegisterBackgroundSignalScheduler(CScheduler& scheduler);
8080
/** Unregister a CScheduler to give callbacks which should run in the background - these callbacks will now be dropped! */
8181
void UnregisterBackgroundSignalScheduler();
82+
/** Call any remaining callbacks on the calling thread */
83+
void FlushBackgroundCallbacks();
8284

8385
void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
8486
void TransactionAddedToMempool(const CTransactionRef &);

0 commit comments

Comments
 (0)