Skip to content

Commit fdeb445

Browse files
committed
Merge #18524: refactor: drop boost::signals2 in validationinterface
d6815a2 refactor: drop boost::signals2 in validationinterface (Russell Yanofsky) Pull request description: Stop using boost::signals2 internally in validationinterface. Replace with std::list and Add/Remove/Clear/Iterate helper functions. Motivation for change is to reduce dependencies and avoid issues happening with boost versions before 1.59: bitcoin/bitcoin#18517, bitcoin/bitcoin#18471 ACKs for top commit: MarcoFalke: ACK d6815a2 laanwj: ACK d6815a2 hebasto: re-ACK d6815a2 promag: ACK d6815a2. Tree-SHA512: 4fc0f14a8446e8616cc142af6c3d36815f3254525d30348ba8e4d4bc74c249a5a8c9bc119bdd1be7ebd7abe0b784bc0c5551a3e156a766890cb2fdd891a95919
2 parents 299544f + d6815a2 commit fdeb445

File tree

2 files changed

+74
-45
lines changed

2 files changed

+74
-45
lines changed

src/validationinterface.cpp

Lines changed: 73 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -16,36 +16,75 @@
1616
#include <unordered_map>
1717
#include <utility>
1818

19-
#include <boost/signals2/signal.hpp>
20-
21-
struct ValidationInterfaceConnections {
22-
boost::signals2::scoped_connection UpdatedBlockTip;
23-
boost::signals2::scoped_connection TransactionAddedToMempool;
24-
boost::signals2::scoped_connection BlockConnected;
25-
boost::signals2::scoped_connection BlockDisconnected;
26-
boost::signals2::scoped_connection TransactionRemovedFromMempool;
27-
boost::signals2::scoped_connection ChainStateFlushed;
28-
boost::signals2::scoped_connection BlockChecked;
29-
boost::signals2::scoped_connection NewPoWValidBlock;
30-
};
31-
19+
//! The MainSignalsInstance manages a list of shared_ptr<CValidationInterface>
20+
//! callbacks.
21+
//!
22+
//! A std::unordered_map is used to track what callbacks are currently
23+
//! registered, and a std::list is to used to store the callbacks that are
24+
//! currently registered as well as any callbacks that are just unregistered
25+
//! and about to be deleted when they are done executing.
3226
struct MainSignalsInstance {
33-
boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
34-
boost::signals2::signal<void (const CTransactionRef &)> TransactionAddedToMempool;
35-
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex)> BlockConnected;
36-
boost::signals2::signal<void (const std::shared_ptr<const CBlock>&, const CBlockIndex* pindex)> BlockDisconnected;
37-
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
38-
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
39-
boost::signals2::signal<void (const CBlock&, const BlockValidationState&)> BlockChecked;
40-
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
41-
27+
private:
28+
Mutex m_mutex;
29+
//! List entries consist of a callback pointer and reference count. The
30+
//! count is equal to the number of current executions of that entry, plus 1
31+
//! if it's registered. It cannot be 0 because that would imply it is
32+
//! unregistered and also not being executed (so shouldn't exist).
33+
struct ListEntry { std::shared_ptr<CValidationInterface> callbacks; int count = 1; };
34+
std::list<ListEntry> m_list GUARDED_BY(m_mutex);
35+
std::unordered_map<CValidationInterface*, std::list<ListEntry>::iterator> m_map GUARDED_BY(m_mutex);
36+
37+
public:
4238
// We are not allowed to assume the scheduler only runs in one thread,
4339
// but must ensure all callbacks happen in-order, so we end up creating
4440
// our own queue here :(
4541
SingleThreadedSchedulerClient m_schedulerClient;
46-
std::unordered_map<CValidationInterface*, ValidationInterfaceConnections> m_connMainSignals;
4742

4843
explicit MainSignalsInstance(CScheduler *pscheduler) : m_schedulerClient(pscheduler) {}
44+
45+
void Register(std::shared_ptr<CValidationInterface> callbacks)
46+
{
47+
LOCK(m_mutex);
48+
auto inserted = m_map.emplace(callbacks.get(), m_list.end());
49+
if (inserted.second) inserted.first->second = m_list.emplace(m_list.end());
50+
inserted.first->second->callbacks = std::move(callbacks);
51+
}
52+
53+
void Unregister(CValidationInterface* callbacks)
54+
{
55+
LOCK(m_mutex);
56+
auto it = m_map.find(callbacks);
57+
if (it != m_map.end()) {
58+
if (!--it->second->count) m_list.erase(it->second);
59+
m_map.erase(it);
60+
}
61+
}
62+
63+
//! Clear unregisters every previously registered callback, erasing every
64+
//! map entry. After this call, the list may still contain callbacks that
65+
//! are currently executing, but it will be cleared when they are done
66+
//! executing.
67+
void Clear()
68+
{
69+
LOCK(m_mutex);
70+
for (auto it = m_list.begin(); it != m_list.end();) {
71+
it = --it->count ? std::next(it) : m_list.erase(it);
72+
}
73+
m_map.clear();
74+
}
75+
76+
template<typename F> void Iterate(F&& f)
77+
{
78+
WAIT_LOCK(m_mutex, lock);
79+
for (auto it = m_list.begin(); it != m_list.end();) {
80+
++it->count;
81+
{
82+
REVERSE_LOCK(lock);
83+
f(*it->callbacks);
84+
}
85+
it = --it->count ? std::next(it) : m_list.erase(it);
86+
}
87+
}
4988
};
5089

5190
static CMainSignals g_signals;
@@ -78,15 +117,7 @@ CMainSignals& GetMainSignals()
78117
void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> pwalletIn) {
79118
// Each connection captures pwalletIn to ensure that each callback is
80119
// executed before pwalletIn is destroyed. For more details see #18338.
81-
ValidationInterfaceConnections& conns = g_signals.m_internals->m_connMainSignals[pwalletIn.get()];
82-
conns.UpdatedBlockTip = g_signals.m_internals->UpdatedBlockTip.connect(std::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
83-
conns.TransactionAddedToMempool = g_signals.m_internals->TransactionAddedToMempool.connect(std::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, std::placeholders::_1));
84-
conns.BlockConnected = g_signals.m_internals->BlockConnected.connect(std::bind(&CValidationInterface::BlockConnected, pwalletIn, std::placeholders::_1, std::placeholders::_2));
85-
conns.BlockDisconnected = g_signals.m_internals->BlockDisconnected.connect(std::bind(&CValidationInterface::BlockDisconnected, pwalletIn, std::placeholders::_1, std::placeholders::_2));
86-
conns.TransactionRemovedFromMempool = g_signals.m_internals->TransactionRemovedFromMempool.connect(std::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, std::placeholders::_1));
87-
conns.ChainStateFlushed = g_signals.m_internals->ChainStateFlushed.connect(std::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, std::placeholders::_1));
88-
conns.BlockChecked = g_signals.m_internals->BlockChecked.connect(std::bind(&CValidationInterface::BlockChecked, pwalletIn, std::placeholders::_1, std::placeholders::_2));
89-
conns.NewPoWValidBlock = g_signals.m_internals->NewPoWValidBlock.connect(std::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, std::placeholders::_1, std::placeholders::_2));
120+
g_signals.m_internals->Register(std::move(pwalletIn));
90121
}
91122

92123
void RegisterValidationInterface(CValidationInterface* callbacks)
@@ -103,15 +134,15 @@ void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> c
103134

104135
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
105136
if (g_signals.m_internals) {
106-
g_signals.m_internals->m_connMainSignals.erase(pwalletIn);
137+
g_signals.m_internals->Unregister(pwalletIn);
107138
}
108139
}
109140

110141
void UnregisterAllValidationInterfaces() {
111142
if (!g_signals.m_internals) {
112143
return;
113144
}
114-
g_signals.m_internals->m_connMainSignals.clear();
145+
g_signals.m_internals->Clear();
115146
}
116147

117148
void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
@@ -151,7 +182,7 @@ void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockInd
151182
// in the same critical section where the chain is updated
152183

153184
auto event = [pindexNew, pindexFork, fInitialDownload, this] {
154-
m_internals->UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload);
185+
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.UpdatedBlockTip(pindexNew, pindexFork, fInitialDownload); });
155186
};
156187
ENQUEUE_AND_LOG_EVENT(event, "%s: new block hash=%s fork block hash=%s (in IBD=%s)", __func__,
157188
pindexNew->GetBlockHash().ToString(),
@@ -161,7 +192,7 @@ void CMainSignals::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockInd
161192

162193
void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) {
163194
auto event = [ptx, this] {
164-
m_internals->TransactionAddedToMempool(ptx);
195+
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionAddedToMempool(ptx); });
165196
};
166197
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
167198
ptx->GetHash().ToString(),
@@ -170,7 +201,7 @@ void CMainSignals::TransactionAddedToMempool(const CTransactionRef &ptx) {
170201

171202
void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
172203
auto event = [ptx, this] {
173-
m_internals->TransactionRemovedFromMempool(ptx);
204+
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.TransactionRemovedFromMempool(ptx); });
174205
};
175206
ENQUEUE_AND_LOG_EVENT(event, "%s: txid=%s wtxid=%s", __func__,
176207
ptx->GetHash().ToString(),
@@ -179,7 +210,7 @@ void CMainSignals::TransactionRemovedFromMempool(const CTransactionRef &ptx) {
179210

180211
void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, const CBlockIndex *pindex) {
181212
auto event = [pblock, pindex, this] {
182-
m_internals->BlockConnected(pblock, pindex);
213+
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockConnected(pblock, pindex); });
183214
};
184215
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
185216
pblock->GetHash().ToString(),
@@ -189,7 +220,7 @@ void CMainSignals::BlockConnected(const std::shared_ptr<const CBlock> &pblock, c
189220
void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex)
190221
{
191222
auto event = [pblock, pindex, this] {
192-
m_internals->BlockDisconnected(pblock, pindex);
223+
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockDisconnected(pblock, pindex); });
193224
};
194225
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s block height=%d", __func__,
195226
pblock->GetHash().ToString(),
@@ -198,7 +229,7 @@ void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock
198229

199230
void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
200231
auto event = [locator, this] {
201-
m_internals->ChainStateFlushed(locator);
232+
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.ChainStateFlushed(locator); });
202233
};
203234
ENQUEUE_AND_LOG_EVENT(event, "%s: block hash=%s", __func__,
204235
locator.IsNull() ? "null" : locator.vHave.front().ToString());
@@ -207,10 +238,10 @@ void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
207238
void CMainSignals::BlockChecked(const CBlock& block, const BlockValidationState& state) {
208239
LOG_EVENT("%s: block hash=%s state=%s", __func__,
209240
block.GetHash().ToString(), state.ToString());
210-
m_internals->BlockChecked(block, state);
241+
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.BlockChecked(block, state); });
211242
}
212243

213244
void CMainSignals::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock> &block) {
214245
LOG_EVENT("%s: block hash=%s", __func__, block->GetHash().ToString());
215-
m_internals->NewPoWValidBlock(pindex, block);
246+
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NewPoWValidBlock(pindex, block); });
216247
}

src/validationinterface.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,7 @@ class CValidationInterface {
171171
* Notifies listeners that a block which builds directly on our current tip
172172
* has been received and connected to the headers tree, though not validated yet */
173173
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& block) {};
174-
friend void ::RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface>);
175-
friend void ::UnregisterValidationInterface(CValidationInterface*);
176-
friend void ::UnregisterAllValidationInterfaces();
174+
friend class CMainSignals;
177175
};
178176

179177
struct MainSignalsInstance;

0 commit comments

Comments
 (0)