Skip to content

Commit a19f641

Browse files
committed
Merge bitcoin/bitcoin#24157: p2p: Replace RecursiveMutex cs_totalBytesSent with Mutex and rename it
709af67 p2p: replace RecursiveMutex `m_total_bytes_sent_mutex` with Mutex (w0xlt) 8be75fd p2p: add assertions and negative TS annotations for `m_total_bytes_sent_mutex` (w0xlt) a237a06 scripted-diff: rename cs_totalBytesSent -> m_total_bytes_sent_mutex (w0xlt) Pull request description: Related to #19303, this PR gets rid of the RecursiveMutex `cs_totalBytesSent` and also adds `AssertLockNotHeld` macros combined with `LOCKS_EXCLUDED` thread safety annotations to avoid recursive locking. ACKs for top commit: jonatack: ACK 709af67 per `git range-diff 7a4ac71 eff7918 709af67`, rebase to master, clang 15 debug build, and build with -Wthread-safety-negative vasild: ACK 709af67 hebasto: ACK 709af67, tested on Ubuntu 22.04. Tree-SHA512: 560b4e6c92b1511911d69185207df6ee809db09b96d97f96430d8d2595dc05c98cc691aaec8a58ef87cf2ab0a98675c210b8ce0be3dedb81e31114bbbfdfd8be
2 parents 1ae65b4 + 709af67 commit a19f641

File tree

2 files changed

+55
-27
lines changed

2 files changed

+55
-27
lines changed

src/net.cpp

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,6 +1567,8 @@ void CConnman::SocketEvents(const std::vector<CNode*>& nodes,
15671567

15681568
void CConnman::SocketHandler()
15691569
{
1570+
AssertLockNotHeld(m_total_bytes_sent_mutex);
1571+
15701572
std::set<SOCKET> recv_set;
15711573
std::set<SOCKET> send_set;
15721574
std::set<SOCKET> error_set;
@@ -1593,6 +1595,8 @@ void CConnman::SocketHandlerConnected(const std::vector<CNode*>& nodes,
15931595
const std::set<SOCKET>& send_set,
15941596
const std::set<SOCKET>& error_set)
15951597
{
1598+
AssertLockNotHeld(m_total_bytes_sent_mutex);
1599+
15961600
for (CNode* pnode : nodes) {
15971601
if (interruptNet)
15981602
return;
@@ -1694,6 +1698,8 @@ void CConnman::SocketHandlerListening(const std::set<SOCKET>& recv_set)
16941698

16951699
void CConnman::ThreadSocketHandler()
16961700
{
1701+
AssertLockNotHeld(m_total_bytes_sent_mutex);
1702+
16971703
SetSyscallSandboxPolicy(SyscallSandboxPolicy::NET);
16981704
while (!interruptNet)
16991705
{
@@ -2578,6 +2584,7 @@ bool CConnman::InitBinds(const Options& options)
25782584

25792585
bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
25802586
{
2587+
AssertLockNotHeld(m_total_bytes_sent_mutex);
25812588
Init(connOptions);
25822589

25832590
if (fListen && !InitBinds(connOptions)) {
@@ -2930,7 +2937,9 @@ void CConnman::RecordBytesRecv(uint64_t bytes)
29302937

29312938
void CConnman::RecordBytesSent(uint64_t bytes)
29322939
{
2933-
LOCK(cs_totalBytesSent);
2940+
AssertLockNotHeld(m_total_bytes_sent_mutex);
2941+
LOCK(m_total_bytes_sent_mutex);
2942+
29342943
nTotalBytesSent += bytes;
29352944

29362945
const auto now = GetTime<std::chrono::seconds>();
@@ -2946,7 +2955,8 @@ void CConnman::RecordBytesSent(uint64_t bytes)
29462955

29472956
uint64_t CConnman::GetMaxOutboundTarget() const
29482957
{
2949-
LOCK(cs_totalBytesSent);
2958+
AssertLockNotHeld(m_total_bytes_sent_mutex);
2959+
LOCK(m_total_bytes_sent_mutex);
29502960
return nMaxOutboundLimit;
29512961
}
29522962

@@ -2957,7 +2967,15 @@ std::chrono::seconds CConnman::GetMaxOutboundTimeframe() const
29572967

29582968
std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() const
29592969
{
2960-
LOCK(cs_totalBytesSent);
2970+
AssertLockNotHeld(m_total_bytes_sent_mutex);
2971+
LOCK(m_total_bytes_sent_mutex);
2972+
return GetMaxOutboundTimeLeftInCycle_();
2973+
}
2974+
2975+
std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle_() const
2976+
{
2977+
AssertLockHeld(m_total_bytes_sent_mutex);
2978+
29612979
if (nMaxOutboundLimit == 0)
29622980
return 0s;
29632981

@@ -2971,14 +2989,15 @@ std::chrono::seconds CConnman::GetMaxOutboundTimeLeftInCycle() const
29712989

29722990
bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) const
29732991
{
2974-
LOCK(cs_totalBytesSent);
2992+
AssertLockNotHeld(m_total_bytes_sent_mutex);
2993+
LOCK(m_total_bytes_sent_mutex);
29752994
if (nMaxOutboundLimit == 0)
29762995
return false;
29772996

29782997
if (historicalBlockServingLimit)
29792998
{
29802999
// keep a large enough buffer to at least relay each block once
2981-
const std::chrono::seconds timeLeftInCycle = GetMaxOutboundTimeLeftInCycle();
3000+
const std::chrono::seconds timeLeftInCycle = GetMaxOutboundTimeLeftInCycle_();
29823001
const uint64_t buffer = timeLeftInCycle / std::chrono::minutes{10} * MAX_BLOCK_SERIALIZED_SIZE;
29833002
if (buffer >= nMaxOutboundLimit || nMaxOutboundTotalBytesSentInCycle >= nMaxOutboundLimit - buffer)
29843003
return true;
@@ -2991,7 +3010,8 @@ bool CConnman::OutboundTargetReached(bool historicalBlockServingLimit) const
29913010

29923011
uint64_t CConnman::GetOutboundTargetBytesLeft() const
29933012
{
2994-
LOCK(cs_totalBytesSent);
3013+
AssertLockNotHeld(m_total_bytes_sent_mutex);
3014+
LOCK(m_total_bytes_sent_mutex);
29953015
if (nMaxOutboundLimit == 0)
29963016
return 0;
29973017

@@ -3005,7 +3025,8 @@ uint64_t CConnman::GetTotalBytesRecv() const
30053025

30063026
uint64_t CConnman::GetTotalBytesSent() const
30073027
{
3008-
LOCK(cs_totalBytesSent);
3028+
AssertLockNotHeld(m_total_bytes_sent_mutex);
3029+
LOCK(m_total_bytes_sent_mutex);
30093030
return nTotalBytesSent;
30103031
}
30113032

@@ -3052,6 +3073,7 @@ bool CConnman::NodeFullyConnected(const CNode* pnode)
30523073

30533074
void CConnman::PushMessage(CNode* pnode, CSerializedNetMsg&& msg)
30543075
{
3076+
AssertLockNotHeld(m_total_bytes_sent_mutex);
30553077
size_t nMessageSize = msg.data.size();
30563078
LogPrint(BCLog::NET, "sending %s (%d bytes) peer=%d\n", msg.m_type, nMessageSize, pnode->GetId());
30573079
if (gArgs.GetBoolArg("-capturemessages", false)) {

src/net.h

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,10 @@ class CConnman
761761
bool m_i2p_accept_incoming;
762762
};
763763

764-
void Init(const Options& connOptions) {
764+
void Init(const Options& connOptions) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex)
765+
{
766+
AssertLockNotHeld(m_total_bytes_sent_mutex);
767+
765768
nLocalServices = connOptions.nLocalServices;
766769
nMaxConnections = connOptions.nMaxConnections;
767770
m_max_outbound_full_relay = std::min(connOptions.m_max_outbound_full_relay, connOptions.nMaxConnections);
@@ -777,7 +780,7 @@ class CConnman
777780
nReceiveFloodSize = connOptions.nReceiveFloodSize;
778781
m_peer_connect_timeout = std::chrono::seconds{connOptions.m_peer_connect_timeout};
779782
{
780-
LOCK(cs_totalBytesSent);
783+
LOCK(m_total_bytes_sent_mutex);
781784
nMaxOutboundLimit = connOptions.nMaxOutboundLimit;
782785
}
783786
vWhitelistedRange = connOptions.vWhitelistedRange;
@@ -792,7 +795,7 @@ class CConnman
792795
bool network_active = true);
793796

794797
~CConnman();
795-
bool Start(CScheduler& scheduler, const Options& options);
798+
bool Start(CScheduler& scheduler, const Options& options) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
796799

797800
void StopThreads();
798801
void StopNodes();
@@ -811,7 +814,7 @@ class CConnman
811814

812815
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
813816

814-
void PushMessage(CNode* pnode, CSerializedNetMsg&& msg);
817+
void PushMessage(CNode* pnode, CSerializedNetMsg&& msg) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
815818

816819
using NodeFn = std::function<void(CNode*)>;
817820
void ForEachNode(const NodeFn& func)
@@ -902,24 +905,22 @@ class CConnman
902905
//! that peer during `net_processing.cpp:PushNodeVersion()`.
903906
ServiceFlags GetLocalServices() const;
904907

905-
uint64_t GetMaxOutboundTarget() const;
908+
uint64_t GetMaxOutboundTarget() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
906909
std::chrono::seconds GetMaxOutboundTimeframe() const;
907910

908911
//! check if the outbound target is reached
909912
//! if param historicalBlockServingLimit is set true, the function will
910913
//! response true if the limit for serving historical blocks has been reached
911-
bool OutboundTargetReached(bool historicalBlockServingLimit) const;
914+
bool OutboundTargetReached(bool historicalBlockServingLimit) const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
912915

913916
//! response the bytes left in the current max outbound cycle
914917
//! in case of no limit, it will always response 0
915-
uint64_t GetOutboundTargetBytesLeft() const;
918+
uint64_t GetOutboundTargetBytesLeft() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
916919

917-
//! returns the time left in the current max outbound cycle
918-
//! in case of no limit, it will always return 0
919-
std::chrono::seconds GetMaxOutboundTimeLeftInCycle() const;
920+
std::chrono::seconds GetMaxOutboundTimeLeftInCycle() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
920921

921922
uint64_t GetTotalBytesRecv() const;
922-
uint64_t GetTotalBytesSent() const;
923+
uint64_t GetTotalBytesSent() const EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
923924

924925
/** Get a unique deterministic randomizer. */
925926
CSipHasher GetDeterministicRandomizer(uint64_t id) const;
@@ -945,6 +946,10 @@ class CConnman
945946
NetPermissionFlags m_permissions;
946947
};
947948

949+
//! returns the time left in the current max outbound cycle
950+
//! in case of no limit, it will always return 0
951+
std::chrono::seconds GetMaxOutboundTimeLeftInCycle_() const EXCLUSIVE_LOCKS_REQUIRED(m_total_bytes_sent_mutex);
952+
948953
bool BindListenPort(const CService& bindAddr, bilingual_str& strError, NetPermissionFlags permissions);
949954
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
950955
bool InitBinds(const Options& options);
@@ -1004,7 +1009,7 @@ class CConnman
10041009
/**
10051010
* Check connected and listening sockets for IO readiness and process them accordingly.
10061011
*/
1007-
void SocketHandler();
1012+
void SocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
10081013

10091014
/**
10101015
* Do the read/write for connected sockets that are ready for IO.
@@ -1017,15 +1022,16 @@ class CConnman
10171022
void SocketHandlerConnected(const std::vector<CNode*>& nodes,
10181023
const std::set<SOCKET>& recv_set,
10191024
const std::set<SOCKET>& send_set,
1020-
const std::set<SOCKET>& error_set);
1025+
const std::set<SOCKET>& error_set)
1026+
EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
10211027

10221028
/**
10231029
* Accept incoming connections, one from each read-ready listening socket.
10241030
* @param[in] recv_set Sockets that are ready for read.
10251031
*/
10261032
void SocketHandlerListening(const std::set<SOCKET>& recv_set);
10271033

1028-
void ThreadSocketHandler();
1034+
void ThreadSocketHandler() EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
10291035
void ThreadDNSAddressSeed();
10301036

10311037
uint64_t CalculateKeyedNetGroup(const CAddress& ad) const;
@@ -1054,7 +1060,7 @@ class CConnman
10541060

10551061
// Network stats
10561062
void RecordBytesRecv(uint64_t bytes);
1057-
void RecordBytesSent(uint64_t bytes);
1063+
void RecordBytesSent(uint64_t bytes) EXCLUSIVE_LOCKS_REQUIRED(!m_total_bytes_sent_mutex);
10581064

10591065
/**
10601066
* Return vector of current BLOCK_RELAY peers.
@@ -1065,14 +1071,14 @@ class CConnman
10651071
static bool NodeFullyConnected(const CNode* pnode);
10661072

10671073
// Network usage totals
1068-
mutable RecursiveMutex cs_totalBytesSent;
1074+
mutable Mutex m_total_bytes_sent_mutex;
10691075
std::atomic<uint64_t> nTotalBytesRecv{0};
1070-
uint64_t nTotalBytesSent GUARDED_BY(cs_totalBytesSent) {0};
1076+
uint64_t nTotalBytesSent GUARDED_BY(m_total_bytes_sent_mutex) {0};
10711077

10721078
// outbound limit & stats
1073-
uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(cs_totalBytesSent) {0};
1074-
std::chrono::seconds nMaxOutboundCycleStartTime GUARDED_BY(cs_totalBytesSent) {0};
1075-
uint64_t nMaxOutboundLimit GUARDED_BY(cs_totalBytesSent);
1079+
uint64_t nMaxOutboundTotalBytesSentInCycle GUARDED_BY(m_total_bytes_sent_mutex) {0};
1080+
std::chrono::seconds nMaxOutboundCycleStartTime GUARDED_BY(m_total_bytes_sent_mutex) {0};
1081+
uint64_t nMaxOutboundLimit GUARDED_BY(m_total_bytes_sent_mutex);
10761082

10771083
// P2P timeout in seconds
10781084
std::chrono::seconds m_peer_connect_timeout;

0 commit comments

Comments
 (0)