| 207 | } |
| 208 | |
| 209 | void Shutdown(NodeContext& node) |
| 210 | { |
| 211 | static Mutex g_shutdown_mutex; |
| 212 | TRY_LOCK(g_shutdown_mutex, lock_shutdown); |
| 213 | if (!lock_shutdown) return; |
| 214 | LogPrintf("%s: In progress...\n", __func__); |
| 215 | Assert(node.args); |
| 216 | |
| 217 | /// Note: Shutdown() must be able to handle cases in which initialization failed part of the way, |
| 218 | /// for example if the data directory was found to be locked. |
| 219 | /// Be sure that anything that writes files or flushes caches only does this if the respective |
| 220 | /// module was initialized. |
| 221 | util::ThreadRename("shutoff"); |
| 222 | if (node.mempool) node.mempool->AddTransactionsUpdated(1); |
| 223 | |
| 224 | StopHTTPRPC(); |
| 225 | StopREST(); |
| 226 | StopRPC(); |
| 227 | StopHTTPServer(); |
| 228 | for (const auto& client : node.chain_clients) { |
| 229 | client->flush(); |
| 230 | } |
| 231 | StopMapPort(); |
| 232 | |
| 233 | // Because these depend on each-other, we make sure that neither can be |
| 234 | // using the other before destroying them. |
| 235 | if (node.peerman) UnregisterValidationInterface(node.peerman.get()); |
| 236 | if (node.connman) node.connman->Stop(); |
| 237 | |
| 238 | StopTorControl(); |
| 239 | |
| 240 | // After everything has been shut down, but before things get flushed, stop the |
| 241 | // CScheduler/checkqueue, scheduler and load block thread. |
| 242 | if (node.chainman && node.chainman->m_load_block.joinable()) node.chainman->m_load_block.join(); |
| 243 | if (node.scheduler) node.scheduler->stop(); |
| 244 | if (node.reverification_scheduler) node.reverification_scheduler->stop(); |
| 245 | StopScriptCheckWorkerThreads(); |
| 246 | |
| 247 | // After the threads that potentially access these pointers have been stopped, |
| 248 | // destruct and reset all to nullptr. |
| 249 | node.peerman.reset(); |
| 250 | node.connman.reset(); |
| 251 | node.banman.reset(); |
| 252 | node.addrman.reset(); |
| 253 | |
| 254 | if (node.mempool && node.mempool->IsLoaded() && node.args->GetBoolArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { |
| 255 | DumpMempool(*node.mempool); |
| 256 | } |
| 257 | |
| 258 | // Drop transactions we were still watching, and record fee estimations. |
| 259 | if (node.fee_estimator) node.fee_estimator->Flush(); |
| 260 | |
| 261 | // FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing |
| 262 | if (node.chainman) { |
| 263 | LOCK(cs_main); |
| 264 | for (CChainState* chainstate : node.chainman->GetAll()) { |
| 265 | if (chainstate->CanFlushToDisk()) { |
| 266 | chainstate->ForceFlushStateToDisk(); |
no test coverage detected