[net] Make cs_inventory nonrecursive#19347
Conversation
jnewbery
commented
Jun 21, 2020
- Remove PushBlockInventory() and PushBlockHash(). These are one-line functions that can easy be inlined into the calling code. Doing so also allows us to eliminate the one place that cs_inventory is recursively locked.
- Make cs_inventory a nonrecursive mutex
- Remove a redundant TRY_LOCK of cs_inventory when deleting CNode.
|
@hebasto : you seem to be on a mutex-cleaning spree. Perhaps you'd be interested in this? |
|
Concept ACK. Made a link here from the tracking issue #19303. |
8c372dd to
eaced81
Compare
hebasto
left a comment
There was a problem hiding this comment.
ACK eaced81501f035193523d1abde4569dfc73ae327, I've verified that mutex does not get locked recursively. Also tested on Linux Mint 20 (x86_64) with the double_lock_detected() function from #19337.
For safety in the future I suggest to merge this PR on top of the #19337 which preserves UB in case of any recursive locking.
|
nit: s/ |
I agree! I'm planning to move this mutex into net processing where it belongs. I'll do the rename at the same time. See https://github.com/jnewbery/bitcoin/commits/2020-06-cs-main-split |
eaced81 to
6db15a8
Compare
|
Does the recent change decrease concurrentness of the code? It seems like a premature optimization a bit, no? |
I think it's fine to expand the lock scope:
|
PushBlockInventory() and PushBlockHash() are functions that can be replaced with single-line statements. This also eliminates the single place that cs_inventory is taken recursively.
cs_inventory is never taken recursively. Make it a non-recursive mutex.
The TRY_LOCK(cs_inventory) in DisconnectNodes() is taken after the CNode object has been removed from vNodes and when the CNode's nRefCount is zero. The only other places that cs_inventory can be taken are: - In ProcessMessages() or SendMessages(), when the CNode's nRefCount must be >0 (see ThreadMessageHandler(), where the refcount is incremented before calling ProcessMessages() and SendMessages()). - In a ForEachNode() lambda in PeerLogicValidation::UpdatedBlockTip(). ForEachNode() locks cs_vNodes and calls the function on the CNode objects in vNodes. Therefore, cs_inventory is never locked by another thread when the TRY_LOCK(cs_inventory) is reached in DisconnectNodes(). Since the only purpose of this TRY_LOCK is to ensure that the lock is not taken by another thread, this always succeeds. Remove the check.
6db15a8 to
e8a2822
Compare
|
I've moved the lock scope change to the correct commit, and also moved it one line up, outside the surrounding if block. It doesn't make any difference here, but makes a commit in a future branch tidier. |
|
utACK e8a2822 |
|
ACK e8a2822 🍬 Show signature and timestampSignature: Timestamp of file with hash |
e8a2822 [net] Don't try to take cs_inventory before deleting CNode (John Newbery) 3556227 [net] Make cs_inventory a non-recursive mutex (John Newbery) 344e831 [net processing] Remove PushBlockInventory and PushBlockHash (John Newbery) Pull request description: - Remove PushBlockInventory() and PushBlockHash(). These are one-line functions that can easy be inlined into the calling code. Doing so also allows us to eliminate the one place that cs_inventory is recursively locked. - Make cs_inventory a nonrecursive mutex - Remove a redundant TRY_LOCK of cs_inventory when deleting CNode. ACKs for top commit: sipa: utACK e8a2822 MarcoFalke: ACK e8a2822 🍬 hebasto: re-ACK e8a2822 Tree-SHA512: dbc721d102cdef7b5827a8f2549daf8b54f543050266999a7ea56c9f36618565b71e31ce0beb1209ba2db43d15388be173355a03fb6db8ad24e2475b145050bd
Summary: > [net processing] Remove PushBlockInventory and PushBlockHash > > PushBlockInventory() and PushBlockHash() are functions that can > be replaced with single-line statements. This also eliminates > the single place that cs_inventory is taken recursively. > [net] Make cs_inventory a non-recursive mutex > > cs_inventory is never taken recursively. Make it a non-recursive mutex. > [net] Don't try to take cs_inventory before deleting CNode > > The TRY_LOCK(cs_inventory) in DisconnectNodes() is taken after the CNode > object has been removed from vNodes and when the CNode's nRefCount is > zero. > > The only other places that cs_inventory can be taken are: > > - In ProcessMessages() or SendMessages(), when the CNode's nRefCount > must be >0 (see ThreadMessageHandler(), where the refcount is > incremented before calling ProcessMessages() and SendMessages()). > - In a ForEachNode() lambda in PeerLogicValidation::UpdatedBlockTip(). > ForEachNode() locks cs_vNodes and calls the function on the CNode > objects in vNodes. > > Therefore, cs_inventory is never locked by another thread when the > TRY_LOCK(cs_inventory) is reached in DisconnectNodes(). Since the > only purpose of this TRY_LOCK is to ensure that the lock is not > taken by another thread, this always succeeds. Remove the check. This is a backport of [[bitcoin/bitcoin#19347 | core#19347]] Test Plan: `ninja all check-all` Reviewers: #bitcoin_abc, deadalnix Reviewed By: #bitcoin_abc, deadalnix Differential Revision: https://reviews.bitcoinabc.org/D9433