Browse Source

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.
0.15
Matt Corallo 8 years ago
parent
commit
3192975f1d
  1. 13
      src/init.cpp
  2. 9
      src/scheduler.cpp
  3. 3
      src/scheduler.h
  4. 1
      src/test/test_bitcoin.cpp
  5. 4
      src/validationinterface.cpp
  6. 2
      src/validationinterface.h

13
src/init.cpp

@ -215,6 +215,19 @@ void Shutdown()
fFeeEstimatesInitialized = false; fFeeEstimatesInitialized = false;
} }
// FlushStateToDisk generates a SetBestChain callback, which we should avoid missing
FlushStateToDisk();
// After there are no more peers/RPC left to give us new data which may generate
// CValidationInterface callbacks, flush them...
GetMainSignals().FlushBackgroundCallbacks();
// Any future callbacks will be dropped. This should absolutely be safe - if
// missing a callback results in an unrecoverable situation, unclean shutdown
// would too. The only reason to do the above flushes is to let the wallet catch
// up with our current chain to avoid any strange pruning edge cases and make
// next startup faster by avoiding rescan.
{ {
LOCK(cs_main); LOCK(cs_main);
if (pcoinsTip != NULL) { if (pcoinsTip != NULL) {

9
src/scheduler.cpp

@ -191,3 +191,12 @@ void SingleThreadedSchedulerClient::AddToProcessQueue(std::function<void (void)>
} }
MaybeScheduleProcessQueue(); MaybeScheduleProcessQueue();
} }
void SingleThreadedSchedulerClient::EmptyQueue() {
bool should_continue = true;
while (should_continue) {
ProcessQueue();
LOCK(m_cs_callbacks_pending);
should_continue = !m_callbacks_pending.empty();
}
}

3
src/scheduler.h

@ -101,6 +101,9 @@ private:
public: public:
SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {} SingleThreadedSchedulerClient(CScheduler *pschedulerIn) : m_pscheduler(pschedulerIn) {}
void AddToProcessQueue(std::function<void (void)> func); void AddToProcessQueue(std::function<void (void)> func);
// Processes all remaining queue members on the calling thread, blocking until queue is empty
void EmptyQueue();
}; };
#endif #endif

1
src/test/test_bitcoin.cpp

@ -94,6 +94,7 @@ TestingSetup::~TestingSetup()
UnregisterNodeSignals(GetNodeSignals()); UnregisterNodeSignals(GetNodeSignals());
threadGroup.interrupt_all(); threadGroup.interrupt_all();
threadGroup.join_all(); threadGroup.join_all();
GetMainSignals().FlushBackgroundCallbacks();
GetMainSignals().UnregisterBackgroundSignalScheduler(); GetMainSignals().UnregisterBackgroundSignalScheduler();
UnloadBlockIndex(); UnloadBlockIndex();
delete pcoinsTip; delete pcoinsTip;

4
src/validationinterface.cpp

@ -44,6 +44,10 @@ void CMainSignals::UnregisterBackgroundSignalScheduler() {
m_internals.reset(nullptr); m_internals.reset(nullptr);
} }
void CMainSignals::FlushBackgroundCallbacks() {
m_internals->m_schedulerClient.EmptyQueue();
}
CMainSignals& GetMainSignals() CMainSignals& GetMainSignals()
{ {
return g_signals; return g_signals;

2
src/validationinterface.h

@ -79,6 +79,8 @@ public:
void RegisterBackgroundSignalScheduler(CScheduler& scheduler); void RegisterBackgroundSignalScheduler(CScheduler& scheduler);
/** Unregister a CScheduler to give callbacks which should run in the background - these callbacks will now be dropped! */ /** Unregister a CScheduler to give callbacks which should run in the background - these callbacks will now be dropped! */
void UnregisterBackgroundSignalScheduler(); void UnregisterBackgroundSignalScheduler();
/** Call any remaining callbacks on the calling thread */
void FlushBackgroundCallbacks();
void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload); void UpdatedBlockTip(const CBlockIndex *, const CBlockIndex *, bool fInitialDownload);
void TransactionAddedToMempool(const CTransactionRef &); void TransactionAddedToMempool(const CTransactionRef &);

Loading…
Cancel
Save