Skip to content

Commit 070803d

Browse files
committed
sync: Replace LockAssertion with WeaklyAssertLockHeld
WeaklyAssertLockHeld does the same thing LockAssertion except it: - Correctly reports file and line number where assertion fails instead of location in sync.h. - Has a simpler syntax that doesn't require declaring an unused variable name. - Should be harder to confuse with AssertLockHeld. Name should indicate it's a weaker assertion not to be preferred when stronger compile time checks are available. This also adds doxygen comments describing AssertLockHeld, WeaklyAssertLockHeld, and AssertLockNotHeld macros.
1 parent a0a422c commit 070803d

File tree

3 files changed

+31
-24
lines changed

3 files changed

+31
-24
lines changed

doc/developer-notes.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ bool ChainstateManager::ProcessNewBlock(...)
793793
}
794794
```
795795
796-
- When Clang Thread Safety Analysis is unable to determine if a mutex is locked, use `LockAssertion` class instances:
796+
- When Clang Thread Safety Analysis is unable to determine if a mutex is locked, use `WeaklyAssertLockHeld`:
797797
798798
```C++
799799
// net_processing.h
@@ -805,7 +805,7 @@ void RelayTransaction(...)
805805
AssertLockHeld(::cs_main);
806806
807807
connman.ForEachNode([&txid, &wtxid](CNode* pnode) {
808-
LockAssertion lock(::cs_main);
808+
WeaklyAssertLockHeld(::cs_main);
809809
...
810810
});
811811
}

src/net_processing.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman& connma
663663
}
664664
}
665665
connman.ForNode(nodeid, [&connman](CNode* pfrom){
666-
LockAssertion lock(::cs_main);
666+
WeaklyAssertLockHeld(::cs_main);
667667
uint64_t nCMPCTBLOCKVersion = (pfrom->GetLocalServices() & NODE_WITNESS) ? 2 : 1;
668668
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
669669
// As per BIP152, we only get 3 of our peers to announce
@@ -1371,7 +1371,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std:
13711371
}
13721372

13731373
m_connman.ForEachNode([this, &pcmpctblock, pindex, &msgMaker, fWitnessEnabled, &hashBlock](CNode* pnode) {
1374-
LockAssertion lock(::cs_main);
1374+
WeaklyAssertLockHeld(::cs_main);
13751375

13761376
// TODO: Avoid the repeated-serialization here
13771377
if (pnode->nVersion < INVALID_CB_NO_BAN_VERSION || pnode->fDisconnect)
@@ -1506,7 +1506,7 @@ void RelayTransaction(const uint256& txid, const uint256& wtxid, const CConnman&
15061506
{
15071507
connman.ForEachNode([&txid, &wtxid](CNode* pnode)
15081508
{
1509-
LockAssertion lock(::cs_main);
1509+
WeaklyAssertLockHeld(::cs_main);
15101510

15111511
CNodeState &state = *State(pnode->GetId());
15121512
if (state.m_wtxid_relay) {
@@ -3999,7 +3999,7 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
39993999
int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max();
40004000

40014001
m_connman.ForEachNode([&](CNode* pnode) {
4002-
LockAssertion lock(::cs_main);
4002+
WeaklyAssertLockHeld(::cs_main);
40034003

40044004
// Ignore non-outbound peers, or nodes marked for disconnect already
40054005
if (!pnode->IsOutboundOrBlockRelayConn() || pnode->fDisconnect) return;
@@ -4016,7 +4016,7 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
40164016
});
40174017
if (worst_peer != -1) {
40184018
bool disconnected = m_connman.ForNode(worst_peer, [&](CNode *pnode) {
4019-
LockAssertion lock(::cs_main);
4019+
WeaklyAssertLockHeld(::cs_main);
40204020

40214021
// Only disconnect a peer that has been connected to us for
40224022
// some reasonable fraction of our check-frequency, to give

src/sync.h

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ void LeaveCritical();
5353
void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line);
5454
std::string LocksHeld();
5555
template <typename MutexType>
56-
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs);
56+
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs);
5757
template <typename MutexType>
5858
void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs);
5959
void DeleteLock(void* cs);
@@ -70,13 +70,34 @@ inline void EnterCritical(const char* pszName, const char* pszFile, int nLine, v
7070
inline void LeaveCritical() {}
7171
inline void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line) {}
7272
template <typename MutexType>
73-
inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(cs) {}
73+
inline void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) {}
7474
template <typename MutexType>
7575
void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, MutexType* cs) EXCLUSIVE_LOCKS_REQUIRED(!cs) {}
7676
inline void DeleteLock(void* cs) {}
7777
inline bool LockStackEmpty() { return true; }
7878
#endif
79-
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
79+
80+
/**
81+
* Assert at compile time and run time that a mutex is locked. Has no effect
82+
* when EXCLUSIVE_LOCKS_REQUIRED annotations are enforced because the runtime
83+
* assertions will never trigger (analogous to asserting an unsigned int is
84+
* greator or equal to 0).
85+
*
86+
* Use of this macro is neither encouraged nor discouraged in new code. It was
87+
* historically used before compile time checks were available, but it may
88+
* still be be useful for virtual methods or std::function callbacks where
89+
* EXCLUSIVE_LOCKS_REQUIRED annotations are not enforced.
90+
*/
91+
#define AssertLockHeld(mutex) [&]() EXCLUSIVE_LOCKS_REQUIRED(mutex) { AssertLockHeldInternal(#mutex, __FILE__, __LINE__, &mutex); }()
92+
93+
/**
94+
* Assert at runtime that a mutex is locked. May be necessary to work around
95+
* EXCLUSIVE_LOCKS_REQUIRED errors when the compiler can't determine that a
96+
* mutex is locked.
97+
*/
98+
#define WeaklyAssertLockHeld(mutex) [&]() ASSERT_EXCLUSIVE_LOCK(mutex) { AssertLockHeldInternal(#mutex, __FILE__, __LINE__, &mutex); }()
99+
100+
/** Assert at compile time and run time that a mutex is not locked. */
80101
#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
81102

82103
/**
@@ -352,18 +373,4 @@ class CSemaphoreGrant
352373
}
353374
};
354375

355-
// Utility class for indicating to compiler thread analysis that a mutex is
356-
// locked (when it couldn't be determined otherwise).
357-
struct SCOPED_LOCKABLE LockAssertion
358-
{
359-
template <typename Mutex>
360-
explicit LockAssertion(Mutex& mutex) EXCLUSIVE_LOCK_FUNCTION(mutex)
361-
{
362-
#ifdef DEBUG_LOCKORDER
363-
AssertLockHeld(mutex);
364-
#endif
365-
}
366-
~LockAssertion() UNLOCK_FUNCTION() {}
367-
};
368-
369376
#endif // BITCOIN_SYNC_H

0 commit comments

Comments
 (0)