Changeset View
Changeset View
Standalone View
Standalone View
doc/developer-notes.md
Show First 20 Lines • Show All 749 Lines • ▼ Show 20 Lines | |||||
Please name variables so that their names do not shadow variables defined in the source code. | Please name variables so that their names do not shadow variables defined in the source code. | ||||
Threads and synchronization | Threads and synchronization | ||||
---------------------------- | ---------------------------- | ||||
- Prefer `Mutex` type to `RecursiveMutex` one | - Prefer `Mutex` type to `RecursiveMutex` one | ||||
- Consistently use [Clang Thread Safety Analysis](https://clang.llvm.org/docs/ThreadSafetyAnalysis.html) annotations to | - Consistently use [Clang Thread Safety Analysis](https://clang.llvm.org/docs/ThreadSafetyAnalysis.html) annotations to | ||||
get compile-time warnings about potential race conditions in code. Combine annotations in function declarations with | get compile-time warnings about potential race conditions or deadlocks in code. | ||||
run-time asserts in function definitions: | |||||
- In functions that are declared separately from where they are defined, the | |||||
thread safety annotations should be added exclusively to the function | |||||
declaration, to avoid shadowing the declaration's annotation and cause false | |||||
positives (lack of compile failure) if a new lock requirement is later added | |||||
to the declaration but the lock is not taken. | |||||
- Prefer locks that are in a class rather than global, and that are | |||||
internal to a class (private or protected) rather than public. | |||||
- Combine annotations in function declarations with run-time asserts in | |||||
function definitions: | |||||
```C++ | ```C++ | ||||
// txmempool.h | // txmempool.h | ||||
class CTxMemPool { | class CTxMemPool { | ||||
public: | public: | ||||
... | ... | ||||
mutable RecursiveMutex cs; | mutable RecursiveMutex cs; | ||||
... | ... | ||||
void UpdateTransactionsFromBlock(...) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, cs); | void UpdateTransactionsFromBlock(...) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, cs); | ||||
... | ... | ||||
} | } | ||||
// txmempool.cpp | // txmempool.cpp | ||||
void CTxMemPool::UpdateTransactionsFromBlock(...) { | void CTxMemPool::UpdateTransactionsFromBlock(...) { | ||||
AssertLockHeld(::cs_main); | AssertLockHeld(::cs_main); | ||||
AssertLockHeld(cs); | AssertLockHeld(cs); | ||||
... | ... | ||||
} | } | ||||
``` | ``` | ||||
```C++ | ```C++ | ||||
// validation.h | // validation.h | ||||
class ChainstateManager { | class CChainState { | ||||
protected: | |||||
... | |||||
Mutex m_chainstate_mutex; | |||||
... | |||||
public: | public: | ||||
... | ... | ||||
bool ProcessNewBlock(...) LOCKS_EXCLUDED(::cs_main); | bool ActivateBestChain( | ||||
BlockValidationState& state, | |||||
std::shared_ptr<const CBlock> pblock = nullptr) | |||||
EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) | |||||
LOCKS_EXCLUDED(::cs_main); | |||||
... | |||||
bool PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) | |||||
EXCLUSIVE_LOCKS_REQUIRED(!m_chainstate_mutex) | |||||
LOCKS_EXCLUDED(::cs_main); | |||||
... | ... | ||||
} | } | ||||
// validation.cpp | // validation.cpp | ||||
bool ChainstateManager::ProcessNewBlock(...) { | bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex) { | ||||
AssertLockNotHeld(m_chainstate_mutex); | |||||
AssertLockNotHeld(::cs_main); | AssertLockNotHeld(::cs_main); | ||||
{ | |||||
LOCK(cs_main); | |||||
... | ... | ||||
LOCK(::cs_main); | } | ||||
... | |||||
return ActivateBestChain(state, std::shared_ptr<const CBlock>()); | |||||
} | } | ||||
``` | ``` | ||||
- Build and run tests with `-DDEBUG_LOCKORDER` to verify that no potential | - Build and run tests with `-DDEBUG_LOCKORDER` to verify that no potential | ||||
deadlocks are introduced. As of 0.12, this is defined by default when | deadlocks are introduced. As of 0.12, this is defined by default when | ||||
configuring with `-DCMAKE_BUILD_TYPE=Debug` | configuring with `-DCMAKE_BUILD_TYPE=Debug` | ||||
- When using `LOCK`/`TRY_LOCK` be aware that the lock exists in the context of | - When using `LOCK`/`TRY_LOCK` be aware that the lock exists in the context of | ||||
▲ Show 20 Lines • Show All 457 Lines • Show Last 20 Lines |