diff options
author | James O'Beirne <james.obeirne@pm.me> | 2020-01-29 09:57:56 -0500 |
---|---|---|
committer | James O'Beirne <james.obeirne@pm.me> | 2020-03-17 14:07:58 -0400 |
commit | c9017ce3bc27665594c9d80f395780d40755bb22 (patch) | |
tree | 36ea710a14db1757ed270ff6e8585eb53427e74f /src/init.cpp | |
parent | 2b081c4568e8019886fdb0f2a57babc73d7487f7 (diff) |
protect g_chainman with cs_main
I'd previously attempted to create a specialized lock for ChainstateManager,
but it turns out that because that lock would be required for functions like
ChainActive() and ChainstateActive(), it created irreconcilable lock inversions
since those functions are used so broadly throughout the codebase.
Instead, I'm just using cs_main to protect the contents of g_chainman.
Co-authored-by: Russell Yanofsky <russ@yanofsky.org>
Diffstat (limited to 'src/init.cpp')
-rw-r--r-- | src/init.cpp | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/src/init.cpp b/src/init.cpp index 56b63c8101..f0ececbb39 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -709,11 +709,17 @@ static void ThreadImport(std::vector<fs::path> vImportFiles) } // scan for better chains in the block chain database, that are not yet connected in the active best chain - BlockValidationState state; - if (!ActivateBestChain(state, chainparams)) { - LogPrintf("Failed to connect best block (%s)\n", state.ToString()); - StartShutdown(); - return; + + // We can't hold cs_main during ActivateBestChain even though we're accessing + // the g_chainman unique_ptrs since ABC requires us not to be holding cs_main, so retrieve + // the relevant pointers before the ABC call. + for (CChainState* chainstate : WITH_LOCK(::cs_main, return g_chainman.GetAll())) { + BlockValidationState state; + if (!chainstate->ActivateBestChain(state, chainparams, nullptr)) { + LogPrintf("Failed to connect best block (%s)\n", state.ToString()); + StartShutdown(); + return; + } } if (gArgs.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { @@ -1622,8 +1628,9 @@ bool AppInitMain(NodeContext& node) } bool failed_rewind{false}; - - for (CChainState* chainstate : g_chainman.GetAll()) { + // Can't hold cs_main while calling RewindBlockIndex, so retrieve the relevant + // chainstates beforehand. + for (CChainState* chainstate : WITH_LOCK(::cs_main, return g_chainman.GetAll())) { if (!fReset) { // Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate. // It both disconnects blocks based on the chainstate, and drops block data in |