Skip to content

Commit 3a2c84a

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#19238: refactor: Make CAddrMan::cs non-recursive
ae98aec refactor: Make CAddrMan::cs non-recursive (Hennadii Stepanov) f5d1c7f Add AssertLockHeld to CAddrMan private functions (Hennadii Stepanov) 5ef1d0b Add thread safety annotations to CAddrMan public functions (Hennadii Stepanov) b138973 refactor: Avoid recursive locking in CAddrMan::Clear (Hennadii Stepanov) f79a664 refactor: Apply consistent pattern for CAddrMan::Check usage (Hennadii Stepanov) 187b7d2 refactor: Avoid recursive locking in CAddrMan::Check (Hennadii Stepanov) f77d9c7 refactor: Fix CAddrMan::Check style (Hennadii Stepanov) 0670397 Make CAddrMan::Check private (Hennadii Stepanov) efc6fac refactor: Avoid recursive locking in CAddrMan::size (Hennadii Stepanov) 2da9554 test: Drop excessive locking in CAddrManTest::SimConnFail (Hennadii Stepanov) Pull request description: This PR replaces `RecursiveMutex CAddrMan::cs` with `Mutex CAddrMan::cs`. All of the related code branches are covered by appropriate lock assertions to insure that the mutex locking policy has not been changed by accident. Related to #19303. Based on #22025, and first three commits belong to it. ACKs for top commit: vasild: ACK ae98aec Tree-SHA512: c3a2d3d955a75befd7e497a802b8c10730e393be9111ca263ad0464d32fae6c7edf9bd173ffb6bc9bb61c4b39073a74eba12979d47f26b0b7b4a861d100942df
2 parents 5c4f0c4 + ae98aec commit 3a2c84a

File tree

4 files changed

+75
-38
lines changed

4 files changed

+75
-38
lines changed

src/addrman.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ double CAddrInfo::GetChance(int64_t nNow) const
7979

8080
CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
8181
{
82+
AssertLockHeld(cs);
83+
8284
const auto it = mapAddr.find(addr);
8385
if (it == mapAddr.end())
8486
return nullptr;
@@ -92,6 +94,8 @@ CAddrInfo* CAddrMan::Find(const CNetAddr& addr, int* pnId)
9294

9395
CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, int* pnId)
9496
{
97+
AssertLockHeld(cs);
98+
9599
int nId = nIdCount++;
96100
mapInfo[nId] = CAddrInfo(addr, addrSource);
97101
mapAddr[addr] = nId;
@@ -104,6 +108,8 @@ CAddrInfo* CAddrMan::Create(const CAddress& addr, const CNetAddr& addrSource, in
104108

105109
void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
106110
{
111+
AssertLockHeld(cs);
112+
107113
if (nRndPos1 == nRndPos2)
108114
return;
109115

@@ -124,6 +130,8 @@ void CAddrMan::SwapRandom(unsigned int nRndPos1, unsigned int nRndPos2)
124130

125131
void CAddrMan::Delete(int nId)
126132
{
133+
AssertLockHeld(cs);
134+
127135
assert(mapInfo.count(nId) != 0);
128136
CAddrInfo& info = mapInfo[nId];
129137
assert(!info.fInTried);
@@ -138,6 +146,8 @@ void CAddrMan::Delete(int nId)
138146

139147
void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
140148
{
149+
AssertLockHeld(cs);
150+
141151
// if there is an entry in the specified bucket, delete it.
142152
if (vvNew[nUBucket][nUBucketPos] != -1) {
143153
int nIdDelete = vvNew[nUBucket][nUBucketPos];
@@ -153,6 +163,8 @@ void CAddrMan::ClearNew(int nUBucket, int nUBucketPos)
153163

154164
void CAddrMan::MakeTried(CAddrInfo& info, int nId)
155165
{
166+
AssertLockHeld(cs);
167+
156168
// remove the entry from all new buckets
157169
for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; bucket++) {
158170
int pos = info.GetBucketPosition(nKey, true, bucket);
@@ -201,6 +213,8 @@ void CAddrMan::MakeTried(CAddrInfo& info, int nId)
201213

202214
void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime)
203215
{
216+
AssertLockHeld(cs);
217+
204218
int nId;
205219

206220
nLastGood = nTime;
@@ -267,6 +281,8 @@ void CAddrMan::Good_(const CService& addr, bool test_before_evict, int64_t nTime
267281

268282
bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimePenalty)
269283
{
284+
AssertLockHeld(cs);
285+
270286
if (!addr.IsRoutable())
271287
return false;
272288

@@ -340,6 +356,8 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
340356

341357
void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
342358
{
359+
AssertLockHeld(cs);
360+
343361
CAddrInfo* pinfo = Find(addr);
344362

345363
// if not found, bail out
@@ -362,7 +380,9 @@ void CAddrMan::Attempt_(const CService& addr, bool fCountFailure, int64_t nTime)
362380

363381
CAddrInfo CAddrMan::Select_(bool newOnly)
364382
{
365-
if (size() == 0)
383+
AssertLockHeld(cs);
384+
385+
if (vRandom.empty())
366386
return CAddrInfo();
367387

368388
if (newOnly && nNew == 0)
@@ -410,6 +430,8 @@ CAddrInfo CAddrMan::Select_(bool newOnly)
410430
#ifdef DEBUG_ADDRMAN
411431
int CAddrMan::Check_()
412432
{
433+
AssertLockHeld(cs);
434+
413435
std::unordered_set<int> setTried;
414436
std::unordered_map<int, int> mapNew;
415437

@@ -487,6 +509,8 @@ int CAddrMan::Check_()
487509

488510
void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size_t max_pct, std::optional<Network> network)
489511
{
512+
AssertLockHeld(cs);
513+
490514
size_t nNodes = vRandom.size();
491515
if (max_pct != 0) {
492516
nNodes = max_pct * nNodes / 100;
@@ -519,6 +543,8 @@ void CAddrMan::GetAddr_(std::vector<CAddress>& vAddr, size_t max_addresses, size
519543

520544
void CAddrMan::Connected_(const CService& addr, int64_t nTime)
521545
{
546+
AssertLockHeld(cs);
547+
522548
CAddrInfo* pinfo = Find(addr);
523549

524550
// if not found, bail out
@@ -539,6 +565,8 @@ void CAddrMan::Connected_(const CService& addr, int64_t nTime)
539565

540566
void CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices)
541567
{
568+
AssertLockHeld(cs);
569+
542570
CAddrInfo* pinfo = Find(addr);
543571

544572
// if not found, bail out
@@ -557,6 +585,8 @@ void CAddrMan::SetServices_(const CService& addr, ServiceFlags nServices)
557585

558586
void CAddrMan::ResolveCollisions_()
559587
{
588+
AssertLockHeld(cs);
589+
560590
for (std::set<int>::iterator it = m_tried_collisions.begin(); it != m_tried_collisions.end();) {
561591
int id_new = *it;
562592

@@ -616,6 +646,8 @@ void CAddrMan::ResolveCollisions_()
616646

617647
CAddrInfo CAddrMan::SelectTriedCollision_()
618648
{
649+
AssertLockHeld(cs);
650+
619651
if (m_tried_collisions.size() == 0) return CAddrInfo();
620652

621653
std::set<int>::iterator it = m_tried_collisions.begin();

src/addrman.h

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ class CAddrMan
231231
*/
232232
template <typename Stream>
233233
void Serialize(Stream& s_) const
234+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
234235
{
235236
LOCK(cs);
236237

@@ -296,10 +297,11 @@ class CAddrMan
296297

297298
template <typename Stream>
298299
void Unserialize(Stream& s_)
300+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
299301
{
300302
LOCK(cs);
301303

302-
Clear();
304+
assert(vRandom.empty());
303305

304306
Format format;
305307
s_ >> Using<CustomUintFormatter<1>>(format);
@@ -452,6 +454,7 @@ class CAddrMan
452454
}
453455

454456
void Clear()
457+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
455458
{
456459
LOCK(cs);
457460
std::vector<int>().swap(vRandom);
@@ -487,26 +490,15 @@ class CAddrMan
487490

488491
//! Return the number of (unique) addresses in all tables.
489492
size_t size() const
493+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
490494
{
491495
LOCK(cs); // TODO: Cache this in an atomic to avoid this overhead
492496
return vRandom.size();
493497
}
494498

495-
//! Consistency check
496-
void Check()
497-
{
498-
#ifdef DEBUG_ADDRMAN
499-
{
500-
LOCK(cs);
501-
int err;
502-
if ((err=Check_()))
503-
LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
504-
}
505-
#endif
506-
}
507-
508499
//! Add a single address.
509500
bool Add(const CAddress &addr, const CNetAddr& source, int64_t nTimePenalty = 0)
501+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
510502
{
511503
LOCK(cs);
512504
bool fRet = false;
@@ -521,6 +513,7 @@ class CAddrMan
521513

522514
//! Add multiple addresses.
523515
bool Add(const std::vector<CAddress> &vAddr, const CNetAddr& source, int64_t nTimePenalty = 0)
516+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
524517
{
525518
LOCK(cs);
526519
int nAdd = 0;
@@ -536,6 +529,7 @@ class CAddrMan
536529

537530
//! Mark an entry as accessible.
538531
void Good(const CService &addr, bool test_before_evict = true, int64_t nTime = GetAdjustedTime())
532+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
539533
{
540534
LOCK(cs);
541535
Check();
@@ -545,6 +539,7 @@ class CAddrMan
545539

546540
//! Mark an entry as connection attempted to.
547541
void Attempt(const CService &addr, bool fCountFailure, int64_t nTime = GetAdjustedTime())
542+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
548543
{
549544
LOCK(cs);
550545
Check();
@@ -554,6 +549,7 @@ class CAddrMan
554549

555550
//! See if any to-be-evicted tried table entries have been tested and if so resolve the collisions.
556551
void ResolveCollisions()
552+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
557553
{
558554
LOCK(cs);
559555
Check();
@@ -563,29 +559,25 @@ class CAddrMan
563559

564560
//! Randomly select an address in tried that another address is attempting to evict.
565561
CAddrInfo SelectTriedCollision()
562+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
566563
{
567-
CAddrInfo ret;
568-
{
569-
LOCK(cs);
570-
Check();
571-
ret = SelectTriedCollision_();
572-
Check();
573-
}
564+
LOCK(cs);
565+
Check();
566+
const CAddrInfo ret = SelectTriedCollision_();
567+
Check();
574568
return ret;
575569
}
576570

577571
/**
578572
* Choose an address to connect to.
579573
*/
580574
CAddrInfo Select(bool newOnly = false)
575+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
581576
{
582-
CAddrInfo addrRet;
583-
{
584-
LOCK(cs);
585-
Check();
586-
addrRet = Select_(newOnly);
587-
Check();
588-
}
577+
LOCK(cs);
578+
Check();
579+
const CAddrInfo addrRet = Select_(newOnly);
580+
Check();
589581
return addrRet;
590582
}
591583

@@ -597,19 +589,19 @@ class CAddrMan
597589
* @param[in] network Select only addresses of this network (nullopt = all).
598590
*/
599591
std::vector<CAddress> GetAddr(size_t max_addresses, size_t max_pct, std::optional<Network> network)
592+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
600593
{
594+
LOCK(cs);
601595
Check();
602596
std::vector<CAddress> vAddr;
603-
{
604-
LOCK(cs);
605-
GetAddr_(vAddr, max_addresses, max_pct, network);
606-
}
597+
GetAddr_(vAddr, max_addresses, max_pct, network);
607598
Check();
608599
return vAddr;
609600
}
610601

611602
//! Outer function for Connected_()
612603
void Connected(const CService &addr, int64_t nTime = GetAdjustedTime())
604+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
613605
{
614606
LOCK(cs);
615607
Check();
@@ -618,6 +610,7 @@ class CAddrMan
618610
}
619611

620612
void SetServices(const CService &addr, ServiceFlags nServices)
613+
EXCLUSIVE_LOCKS_REQUIRED(!cs)
621614
{
622615
LOCK(cs);
623616
Check();
@@ -633,8 +626,8 @@ class CAddrMan
633626
FastRandomContext insecure_rand;
634627

635628
private:
636-
//! critical section to protect the inner data structures
637-
mutable RecursiveMutex cs;
629+
//! A mutex to protect the inner data structures.
630+
mutable Mutex cs;
638631

639632
//! Serialization versions.
640633
enum Format : uint8_t {
@@ -725,6 +718,19 @@ class CAddrMan
725718
//! Return a random to-be-evicted tried table address.
726719
CAddrInfo SelectTriedCollision_() EXCLUSIVE_LOCKS_REQUIRED(cs);
727720

721+
//! Consistency check
722+
void Check()
723+
EXCLUSIVE_LOCKS_REQUIRED(cs)
724+
{
725+
#ifdef DEBUG_ADDRMAN
726+
AssertLockHeld(cs);
727+
const int err = Check_();
728+
if (err) {
729+
LogPrintf("ADDRMAN CONSISTENCY CHECK FAILED!!! err=%i\n", err);
730+
}
731+
#endif
732+
}
733+
728734
#ifdef DEBUG_ADDRMAN
729735
//! Perform consistency check. Returns an error code or zero.
730736
int Check_() EXCLUSIVE_LOCKS_REQUIRED(cs);

src/test/addrman_tests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ class CAddrManTest : public CAddrMan
7474
// Simulates connection failure so that we can test eviction of offline nodes
7575
void SimConnFail(const CService& addr)
7676
{
77-
LOCK(cs);
7877
int64_t nLastSuccess = 1;
79-
Good_(addr, true, nLastSuccess); // Set last good connection in the deep past.
78+
// Set last good connection in the deep past.
79+
Good(addr, true, nLastSuccess);
8080

8181
bool count_failure = false;
8282
int64_t nLastTry = GetAdjustedTime()-61;

src/test/fuzz/addrman.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ FUZZ_TARGET_INIT(addrman, initialize_addrman)
107107
/* max_addresses */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
108108
/* max_pct */ fuzzed_data_provider.ConsumeIntegralInRange<size_t>(0, 4096),
109109
/* network */ std::nullopt);
110-
(void)/*const_*/addr_man.Check();
111110
(void)/*const_*/addr_man.Select(fuzzed_data_provider.ConsumeBool());
112111
(void)const_addr_man.size();
113112
CDataStream data_stream(SER_NETWORK, PROTOCOL_VERSION);

0 commit comments

Comments
 (0)