Inside Bitcoin
Opening the selected file…
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
251//252// Thread management and startup/shutdown:253//254// The network-processing threads are all part of a thread group255// created by AppInit() or the Qt main() function.256//257// A clean exit happens when the SignalInterrupt object is triggered, which258// makes the main thread's SignalInterrupt::wait() call return, and join all259// other ongoing threads in the thread group to the main thread.260// Shutdown() is then called to clean up database connections, and stop other261// threads that should only be stopped after the main network-processing262// threads have exited.263//264// Shutdown for Qt is very similar, only it uses a QTimer to detect265// ShutdownRequested() getting set, and then does the normal Qt266// shutdown thing.267//269bool ShutdownRequested(node::NodeContext& node)270{271return bool{*Assert(node.shutdown_signal)};272}274#if HAVE_SYSTEM275static void ShutdownNotify(const ArgsManager& args)276{277std::vector<std::thread> threads;278for (const auto& cmd : args.GetArgs("-shutdownnotify")) {279threads.emplace_back(runCommand, cmd);280}281for (auto& t : threads) {282t.join();283}284}285#endif287void Interrupt(NodeContext& node)288{289#if HAVE_SYSTEM290ShutdownNotify(*node.args);291#endif292// Wake any threads that may be waiting for the tip to change.293if (node.notifications) WITH_LOCK(node.notifications->m_tip_block_mutex, node.notifications->m_tip_block_cv.notify_all());294InterruptHTTPServer();295InterruptHTTPRPC();296InterruptRPC();297InterruptREST();298if (node.tor_controller) {299node.tor_controller->Interrupt();300}301InterruptMapPort();302if (node.connman)303node.connman->Interrupt();304for (auto* index : node.indexes) {305index->Interrupt();306}307}309void Shutdown(NodeContext& node)310{311static Mutex g_shutdown_mutex;312TRY_LOCK(g_shutdown_mutex, lock_shutdown);313if (!lock_shutdown) return;314LogInfo("Shutdown in progress...");315Assert(node.args);317/// Note: Shutdown() must be able to handle cases in which initialization failed part of the way,318/// for example if the data directory was found to be locked.319/// Be sure that anything that writes files or flushes caches only does this if the respective320/// module was initialized.321util::ThreadRename("shutoff");322if (node.mempool) node.mempool->AddTransactionsUpdated(1);324StopHTTPRPC();325StopREST();326StopRPC();327StopHTTPServer();328for (auto& client : node.chain_clients) {329try {330client->stop();331} catch (const ipc::Exception& e) {332LogDebug(BCLog::IPC, "Chain client did not disconnect cleanly: %s", e.what());333client.reset();334}335}336StopMapPort();338// Because these depend on each-other, we make sure that neither can be339// using the other before destroying them.340if (node.peerman && node.validation_signals) node.validation_signals->UnregisterValidationInterface(node.peerman.get());341if (node.connman) node.connman->Stop();343if (node.tor_controller) {344node.tor_controller->Join();345node.tor_controller.reset();346}348if (node.background_init_thread.joinable()) node.background_init_thread.join();349// After everything has been shut down, but before things get flushed, stop the350// the scheduler. After this point, SyncWithValidationInterfaceQueue() should not be called anymore351// as this would prevent the shutdown from completing.352if (node.scheduler) node.scheduler->stop();354// After the threads that potentially access these pointers have been stopped,355// destruct and reset all to nullptr.356node.peerman.reset();357node.connman.reset();358node.banman.reset();359node.addrman.reset();360node.netgroupman.reset();362if (node.mempool && node.mempool->GetLoadTried() && ShouldPersistMempool(*node.args)) {363DumpMempool(*node.mempool, MempoolPath(*node.args));364}366// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing367if (node.chainman) {368LOCK(cs_main);369for (const auto& chainstate : node.chainman->m_chainstates) {370if (chainstate->CanFlushToDisk()) {371chainstate->ForceFlushStateToDisk();372}373}374}376// After there are no more peers/RPC left to give us new data which may generate377// CValidationInterface callbacks, flush them...378if (node.validation_signals) node.validation_signals->FlushBackgroundCallbacks();380// Once callbacks drain, drop tracked transactions, save estimates, and unregister the estimator381if (node.fee_estimator_man) {382node.fee_estimator_man->ShutdownFlush();383if (node.validation_signals) {384node.validation_signals->UnregisterValidationInterface(node.fee_estimator_man.get());385}386}388// Stop and delete all indexes only after flushing background callbacks.389for (auto* index : node.indexes) index->Stop();390if (g_txindex) g_txindex.reset();391if (g_txospenderindex) g_txospenderindex.reset();392if (g_coin_stats_index) g_coin_stats_index.reset();393DestroyAllBlockFilterIndexes();394node.indexes.clear(); // all instances are nullptr now396// Callbacks queued by this final chainstate flush will not run during shutdown397if (node.chainman) {398LOCK(cs_main);399for (const auto& chainstate : node.chainman->m_chainstates) {400if (chainstate->CanFlushToDisk()) {401chainstate->ForceFlushStateToDisk();402chainstate->ResetCoinsViews();403}404}405}407// If any -ipcbind clients are still connected, disconnect them now so they408// do not block shutdown.409if (interfaces::Ipc* ipc = node.init->ipc()) {410ipc->disconnectIncoming();411}413#ifdef ENABLE_ZMQ414if (g_zmq_notification_interface) {415if (node.validation_signals) node.validation_signals->UnregisterValidationInterface(g_zmq_notification_interface.get());416g_zmq_notification_interface.reset();417}418#endif420node.chain_clients.clear();421if (node.validation_signals) {422node.validation_signals->UnregisterAllValidationInterfaces();423}424node.fee_estimator_man.reset();425node.mempool.reset();426node.chainman.reset();427node.validation_signals.reset();428node.scheduler.reset();429node.ecc_context.reset();430node.kernel.reset();432RemovePidFile(*node.args);434LogInfo("Shutdown done");435}437/**438* Signal handlers are very limited in what they are allowed to do.439* The execution context the handler is invoked in is not guaranteed,440* so we restrict handler operations to just touching variables:441*/442#ifndef WIN32443static void HandleSIGTERM(int)444{445// Return value is intentionally ignored because there is not a better way446// of handling this failure in a signal handler.447(void)(*Assert(g_shutdown))();448}450static void HandleSIGHUP(int)451{452LogInstance().m_reopen_file = true;453}454#else455static BOOL WINAPI consoleCtrlHandler(DWORD dwCtrlType)456{457if (!(*Assert(g_shutdown))()) {458LogError("Failed to send shutdown signal on Ctrl-C\n");459return false;460}461Sleep(INFINITE);462return true;463}464#endif466#ifndef WIN32467static void registerSignalHandler(int signal, void(*handler)(int))468{469struct sigaction sa;470sa.sa_handler = handler;471sigemptyset(&sa.sa_mask);472sa.sa_flags = 0;473sigaction(signal, &sa, nullptr);474}475#endif477void SetupServerArgs(ArgsManager& argsman, bool can_listen_ipc)478{479SetupHelpOptions(argsman);480argsman.AddArg("-help-debug", "Print help message with debugging options and exit", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); // server-only for now482init::AddLoggingArgs(argsman);484const auto defaultBaseParams = CreateBaseChainParams(ChainType::MAIN);485const auto testnetBaseParams = CreateBaseChainParams(ChainType::TESTNET);486const auto testnet4BaseParams = CreateBaseChainParams(ChainType::TESTNET4);487const auto signetBaseParams = CreateBaseChainParams(ChainType::SIGNET);488const auto regtestBaseParams = CreateBaseChainParams(ChainType::REGTEST);489const auto defaultChainParams = CreateChainParams(argsman, ChainType::MAIN);490const auto testnetChainParams = CreateChainParams(argsman, ChainType::TESTNET);491const auto testnet4ChainParams = CreateChainParams(argsman, ChainType::TESTNET4);492const auto signetChainParams = CreateChainParams(argsman, ChainType::SIGNET);493const auto regtestChainParams = CreateChainParams(argsman, ChainType::REGTEST);495// Hidden Options496std::vector<std::string> hidden_args = {497"-dbcrashratio", "-forcecompactdb",498// GUI args. These will be overwritten by SetupUIArgs for the GUI499"-choosedatadir", "-lang=<lang>", "-min", "-resetguisettings", "-splash", "-uiplatform"};