Inside Bitcoin
Opening the selected file…
Inside Bitcoin
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//! Backwards-compatible constructor for previous (deprecated) logging callback signature252EventLoop(const char* exe_name, std::function<void(bool, std::string)> old_callback, void* context = nullptr)253: EventLoop(exe_name,254LogFn{[old_callback = std::move(old_callback)](LogMessage log_data) {old_callback(log_data.level == Log::Raise, std::move(log_data.message));}},255context){}257~EventLoop();259//! Run event loop. Does not return until shutdown. This should only be260//! called once from the m_thread_id thread. This will block until261//! the m_num_refs reference count is 0.262void loop();264//! Run function on event loop thread. Does not return until function completes.265//! Must be called while the loop() function is active.266void post(kj::Function<void()> fn);268//! Wrapper around EventLoop::post that takes advantage of the269//! fact that callable will not go out of scope to avoid requirement that it270//! be copyable.271template <typename Callable>272void sync(Callable&& callable)273{274post(std::forward<Callable>(callable));275}277//! Register cleanup function to run on asynchronous worker thread without278//! blocking the event loop thread.279void addAsyncCleanup(std::function<void()> fn);281//! Start asynchronous worker thread if necessary. This is only done if282//! there are ProxyServerBase::m_impl objects that need to be destroyed283//! asynchronously, without tying up the event loop thread. This can happen284//! when an interface does not declare a destroy() method that would allow285//! the client to wait for the destructor to finish and run it on a286//! dedicated thread. It can also happen whenever this is a broken287//! connection and the client is no longer around to call the destructors288//! and the server objects need to be garbage collected. In both cases, it289//! is important that ProxyServer::m_impl destructors do not run on the290//! eventloop thread because they may need it to do I/O if they perform291//! other IPC calls.292void startAsyncThread() MP_REQUIRES(m_mutex);294//! Check if loop should exit.295bool done() const MP_REQUIRES(m_mutex);297//! Process name included in thread names so combined debug output from298//! multiple processes is easier to understand.299const char* m_exe_name;301//! ID of the event loop thread302std::thread::id m_thread_id = std::this_thread::get_id();304//! Handle of an async worker thread. Joined on destruction. Unset if async305//! method has not been called.306std::thread m_async_thread;308//! Callback function to run on event loop thread during post() or sync() call.309kj::Function<void()>* m_post_fn MP_GUARDED_BY(m_mutex) = nullptr;311//! Callback functions to run on async thread.312std::optional<CleanupList> m_async_fns MP_GUARDED_BY(m_mutex);314//! Pipe read handle used to wake up the event loop thread.315int m_wait_fd = -1;317//! Pipe write handle used to wake up the event loop thread.318int m_post_fd = -1;320//! Number of EventLoopRef instances referencing this event loop. This is a321//! sum of the number of client and server objects (Connection, ProxyClient,322//! ProxyServer) using the loop, plus temporary references held while323//! posting functions to the loop, plus any references held by external code324//! to keep the loop running. The loop() method exits when this count drops325//! to 0 (and m_async_fns is empty).326int m_num_refs MP_GUARDED_BY(m_mutex) = 0;328//! Mutex and condition variable used to post tasks to event loop and async329//! thread.330Mutex m_mutex;331std::condition_variable m_cv;333//! Capnp IO context.334kj::AsyncIoContext m_io_context;336//! Capnp error handler. Needs to outlive m_task_set.337LoggingErrorHandler m_error_handler{*this};339//! Capnp list of pending promises.340std::unique_ptr<kj::TaskSet> m_task_set;342//! List of connections.343std::list<Connection> m_incoming_connections;345//! Logging options346LogOptions m_log_opts;348//! External context pointer.349void* m_context;351//! Hook called when ProxyServer<ThreadMap>::makeThread() is called.352std::function<void()> testing_hook_makethread;354//! Hook called on the worker thread inside makeThread(), after the thread355//! context is set up and thread_context promise is fulfilled, but before it356//! starts waiting for requests.357std::function<void()> testing_hook_makethread_created;359//! Hook called on the worker thread when it starts to execute an async360//! request. Used by tests to control timing or inject behavior at this361//! point in execution.362std::function<void()> testing_hook_async_request_start;364//! Hook called on the worker thread just before returning results.365std::function<void()> testing_hook_async_request_done;367//! Hook called on the event loop thread when a client has connected.368std::function<void()> testing_hook_connected;370//! Hook called on the event loop thread when a client has disconnected.371std::function<void()> testing_hook_disconnected;372};374//! Single element task queue used to handle recursive capnp calls. (If the375//! server makes a callback into the client in the middle of a request, while the client376//! thread is blocked waiting for server response, this is what allows the377//! client to run the request in the same thread, the same way code would run in a378//! single process, with the callback sharing the same thread stack as the original379//! call.) To support this, the clientInvoke function calls Waiter::wait() to380//! block the client IPC thread while initial request is in progress. Then if381//! there is a callback, it is executed with Waiter::post().382//!383//! The Waiter class is also used server-side by `ProxyServer<Thread>::post()`384//! to execute IPC calls on worker threads.385struct Waiter386{387Waiter() = default;389template <typename Fn>390bool post(Fn&& fn)391{392const Lock lock(m_mutex);393if (m_fn) return false;394m_fn = std::forward<Fn>(fn);395m_cv.notify_all();396return true;397}399template <class Predicate>400void wait(Lock& lock, Predicate pred) MP_REQUIRES(m_mutex)401{402m_cv.wait(lock.m_lock, [&]() MP_REQUIRES(m_mutex) {403// Important for this to be "while (m_fn)", not "if (m_fn)" to avoid404// a lost-wakeup bug. A new m_fn and m_cv notification might be sent405// after the fn() call and before the lock.lock() call in this loop406// in the case where a capnp response is sent and a brand new407// request is immediately received.408while (m_fn) {409auto fn = std::move(*m_fn);410m_fn.reset();411Unlock(lock, fn);412}413const bool done = pred();414return done;415});416}418//! Mutex mainly used internally by waiter class, but also used externally419//! to guard access to related state. Specifically, since the thread_local420//! ThreadContext struct owns a Waiter, the Waiter::m_mutex is used to guard421//! access to other parts of the struct to avoid needing to deal with more422//! mutexes than necessary. This mutex can be held at the same time as423//! EventLoop::m_mutex as long as Waiter::mutex is locked first and424//! EventLoop::m_mutex is locked second.425Mutex m_mutex;426std::condition_variable m_cv MP_GUARDED_BY(m_mutex);427std::optional<kj::Function<void()>> m_fn MP_GUARDED_BY(m_mutex);428};430//! Object holding network & rpc state associated with either an incoming server431//! connection, or an outgoing client connection. It must be created and destroyed432//! on the event loop thread.433//! In addition to Cap'n Proto state, it also holds lists of callbacks to run434//! when the connection is closed.435class Connection436{437public:438Connection(EventLoop& loop, kj::Own<kj::AsyncIoStream>&& stream_)439: m_loop(loop), m_stream(kj::mv(stream_)),440m_network(*m_stream, ::capnp::rpc::twoparty::Side::CLIENT, ::capnp::ReaderOptions()),441m_rpc_system(::capnp::makeRpcClient(m_network)) {}442Connection(EventLoop& loop,443kj::Own<kj::AsyncIoStream>&& stream_,444const std::function<::capnp::Capability::Client(Connection&)>& make_client)445: m_loop(loop), m_stream(kj::mv(stream_)),446m_network(*m_stream, ::capnp::rpc::twoparty::Side::SERVER, ::capnp::ReaderOptions()),447m_rpc_system(::capnp::makeRpcServer(m_network, make_client(*this))) {}449//! Run cleanup functions. Must be called from the event loop thread. First450//! calls synchronous cleanup functions while blocked (to free capnp451//! Capability::Client handles owned by ProxyClient objects), then schedules452//! asynchronous cleanup functions to run in a worker thread (to run453//! destructors of m_impl instances owned by ProxyServer objects).454~Connection();456//! Register synchronous cleanup function to run on event loop thread (with457//! access to capnp thread local variables) when disconnect() is called.458//! any new i/o.459CleanupIt addSyncCleanup(std::function<void()> fn);460void removeSyncCleanup(CleanupIt it);462//! Add disconnect handler.463template <typename F>464void onDisconnect(F&& f)465{466// Add disconnect handler to local TaskSet to ensure it is canceled and467// will never run after connection object is destroyed. But when disconnect468// handler fires, do not call the function f right away, instead add it469// to the EventLoop TaskSet to avoid "Promise callback destroyed itself"470// error in the typical case where f deletes this Connection object.471m_on_disconnect.add(m_network.onDisconnect().then(472[f = std::forward<F>(f), this]() mutable { m_loop->m_task_set->add(kj::evalLater(kj::mv(f))); }));473}475EventLoopRef m_loop;476kj::Own<kj::AsyncIoStream> m_stream;477LoggingErrorHandler m_error_handler{*m_loop};478//! TaskSet used to cancel the m_network.onDisconnect() handler for remote479//! disconnections, if the connection is closed locally first by deleting480//! this Connection object.481kj::TaskSet m_on_disconnect{m_error_handler};482::capnp::TwoPartyVatNetwork m_network;483std::optional<::capnp::RpcSystem<::capnp::rpc::twoparty::VatId>> m_rpc_system;485// ThreadMap interface client, used to create a remote server thread when an486// client IPC call is being made for the first time from a new thread.487ThreadMap::Client m_thread_map{nullptr};489//! Collection of server-side IPC worker threads (ProxyServer<Thread> objects previously returned by490//! ThreadMap.makeThread) used to service requests to clients.491::capnp::CapabilityServerSet<Thread> m_threads;493//! A thread created by makePool with associated pending work queue. Vector is filled once by makePool() and never resized.494struct PoolSlot {495Thread::Client client;496size_t depth{0};497};498std::vector<PoolSlot> m_thread_pool;500//! Canceler for canceling promises that we want to discard when the
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.