Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
proxy-io.h
Go to the documentation of this file.
1// Copyright (c) The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#ifndef MP_PROXY_IO_H
6#define MP_PROXY_IO_H
7
8#include <mp/proxy.h>
9#include <mp/util.h>
10
11#include <mp/proxy.capnp.h>
12
13#include <capnp/rpc-twoparty.h>
14
15#include <any>
16#include <assert.h>
17#include <algorithm>
18#include <condition_variable>
19#include <cstdlib>
20#include <functional>
21#include <kj/function.h>
22#include <kj/io.h>
23#include <map>
24#include <memory>
25#include <optional>
26#include <ranges>
27#include <sstream>
28#include <string>
29#include <thread>
30
31namespace mp {
32struct ThreadContext;
33struct Listener;
34
39
48
49template <typename ProxyServer, typename CallContext_>
76
77template <typename Interface, typename Params, typename Results>
78using ServerContext = ServerInvokeContext<ProxyServer<Interface>, ::capnp::CallContext<Params, Results>>;
79
80template <>
81struct ProxyClient<Thread> : public ProxyClientBase<Thread, ::capnp::Void>
82{
84 // https://stackoverflow.com/questions/22357887/comparing-two-mapiterators-why-does-it-need-the-copy-constructor-of-stdpair
85 ProxyClient(const ProxyClient&) = delete;
87
97 std::optional<CleanupIt> m_disconnect_cb;
98};
100template <>
101struct ProxyServer<Thread> final : public Thread::Server
102{
103public:
104 ProxyServer(Connection& connection, ThreadContext& thread_context, std::thread&& thread);
105 ~ProxyServer();
106 kj::Promise<void> getName(GetNameContext context) override;
107
112 template<typename T, typename Fn>
113 kj::Promise<T> post(Fn&& fn);
114
117 std::thread m_thread;
120 kj::Promise<void> m_thread_ready{kj::READY_NOW};
121};
122
124class LoggingErrorHandler : public kj::TaskSet::ErrorHandler
125{
126public:
128 void taskFailed(kj::Exception&& exception) override;
130};
131
133enum class Log {
134 Trace = 0,
135 Debug,
136 Info,
137 Warning,
138 Error,
139 Raise,
140};
141
142kj::StringPtr KJ_STRINGIFY(Log flags);
143
145
147 std::string message;
148
151};
152
153using LogFn = std::function<void(LogMessage)>;
154
159
162 size_t max_chars{200};
163
167};
168
170{
171public:
172 Logger(const LogOptions& options, Log log_level) : m_options(options), m_log_level(log_level) {}
173
174 Logger(Logger&&) = delete;
175 Logger& operator=(Logger&&) = delete;
176 Logger(const Logger&) = delete;
177 Logger& operator=(const Logger&) = delete;
178
179 ~Logger() noexcept(false)
180 {
181 if (enabled()) m_options.log_fn({std::move(m_buffer).str(), m_log_level});
182 }
183
184 template <typename T>
185 friend Logger& operator<<(Logger& logger, T&& value)
186 {
187 if (logger.enabled()) logger.m_buffer << std::forward<T>(value);
188 return logger;
189 }
190
191 template <typename T>
192 friend Logger& operator<<(Logger&& logger, T&& value)
193 {
194 return logger << std::forward<T>(value);
195 }
196
197 explicit operator bool() const
198 {
199 return enabled();
200 }
201
202private:
203 bool enabled() const
204 {
206 }
207
210 std::ostringstream m_buffer;
211};
212
213#define MP_LOGPLAIN(loop, ...) if (mp::Logger logger{(loop).m_log_opts, __VA_ARGS__}; logger) logger
214
215#define MP_LOG(loop, ...) MP_LOGPLAIN(loop, __VA_ARGS__) << "{" << LongThreadName((loop).m_exe_name) << "} "
216
217std::string LongThreadName(const char* exe_name);
218
220Stream MakeStream(EventLoop&loop, SocketId socket);
221
248{
249public:
251 EventLoop(const char* exe_name, LogFn log_fn, void* context = nullptr)
252 : EventLoop(exe_name, LogOptions{std::move(log_fn)}, context){}
253
255 EventLoop(const char* exe_name, LogOptions log_opts, void* context = nullptr);
256
258 EventLoop(const char* exe_name, std::function<void(bool, std::string)> old_callback, void* context = nullptr)
260 LogFn{[old_callback = std::move(old_callback)](LogMessage log_data) {old_callback(log_data.level == Log::Raise, std::move(log_data.message));}},
261 context){}
262
263 ~EventLoop();
264
268 void loop();
269
272 void sync(kj::FunctionParam<void()> fn);
273
276 void addAsyncCleanup(std::function<void()> fn);
277
289 void startAsyncThread() MP_REQUIRES(m_mutex);
290
292 bool done() const MP_REQUIRES(m_mutex);
293
296
298 auto incomingConnections() { return std::views::all(m_incoming_connections); }
299
302 const char* m_exe_name;
303
305 std::thread::id m_thread_id = std::this_thread::get_id();
306
309 std::thread m_async_thread;
310
312 kj::FunctionParam<void()>* m_sync_fn MP_GUARDED_BY(m_mutex) = nullptr;
313
315 std::optional<CleanupList> m_async_fns MP_GUARDED_BY(m_mutex);
316
318 kj::Own<kj::AsyncIoStream> m_wait_stream;
319 kj::Own<kj::AsyncIoStream> m_post_stream;
320
322 kj::Own<kj::OutputStream> m_post_writer;
323
330 int m_num_refs MP_GUARDED_BY(m_mutex) = 0;
331
335 std::condition_variable m_cv;
336
338 kj::AsyncIoContext m_io_context;
339
341 LoggingErrorHandler m_error_handler{*this};
342
344 std::unique_ptr<kj::TaskSet> m_task_set;
345
348
351
354
357
362
367
370
372 std::function<void()> testing_hook_connected;
373
376
381 std::function<void(std::any)> testing_hook_misc;
382};
383
395struct Waiter
396{
397 Waiter() = default;
398
399 template <typename Fn>
400 bool post(Fn&& fn)
401 {
402 const Lock lock(m_mutex);
403 if (m_fn) return false;
404 m_fn = std::forward<Fn>(fn);
405 m_cv.notify_all();
406 return true;
407 }
408
409 template <class Predicate>
410 void wait(Lock& lock, Predicate pred) MP_REQUIRES(m_mutex)
411 {
412 m_cv.wait(lock.m_lock, [&]() MP_REQUIRES(m_mutex) {
413 // Important for this to be "while (m_fn)", not "if (m_fn)" to avoid
414 // a lost-wakeup bug. A new m_fn and m_cv notification might be sent
415 // after the fn() call and before the lock.lock() call in this loop
416 // in the case where a capnp response is sent and a brand new
417 // request is immediately received.
418 while (m_fn) {
419 auto fn = std::move(*m_fn);
420 m_fn.reset();
421 Unlock(lock, fn);
422 }
423 const bool done = pred();
424 return done;
425 });
426 }
427
436 std::condition_variable m_cv MP_GUARDED_BY(m_mutex);
437 std::optional<kj::Function<void()>> m_fn MP_GUARDED_BY(m_mutex);
438};
439
446{
447public:
448 Connection(EventLoop& loop, kj::Own<kj::AsyncIoStream>&& stream_)
449 : m_loop(loop), m_stream(kj::mv(stream_)),
450 m_network(*m_stream, ::capnp::rpc::twoparty::Side::CLIENT, ::capnp::ReaderOptions()),
451 m_rpc_system(::capnp::makeRpcClient(m_network)) {}
453 kj::Own<kj::AsyncIoStream>&& stream_,
454 const std::function<::capnp::Capability::Client(Connection&)>& make_client)
455 : m_loop(loop), m_stream(kj::mv(stream_)),
456 m_network(*m_stream, ::capnp::rpc::twoparty::Side::SERVER, ::capnp::ReaderOptions()),
457 m_rpc_system(::capnp::makeRpcServer(m_network, make_client(*this))) {}
458
464 ~Connection() noexcept(false);
465
469 CleanupIt addSyncCleanup(std::function<void()> fn);
470 void removeSyncCleanup(CleanupIt it);
471
474 void onDisconnect(F&& f)
475 {
476 // Add disconnect handler to local TaskSet to ensure it is canceled and
477 // will never run after connection object is destroyed. But when disconnect
478 // handler fires, do not call the function f right away, instead add it
479 // to the EventLoop TaskSet to avoid "Promise callback destroyed itself"
480 // error in the typical case where f deletes this Connection object.
481 m_on_disconnect.add(m_network.onDisconnect().then(
482 [f = std::forward<F>(f), this]() mutable { m_loop->m_task_set->add(kj::evalLater(kj::mv(f))); }));
483 }
484
486 kj::Own<kj::AsyncIoStream> m_stream;
487 LoggingErrorHandler m_error_handler{*m_loop};
491 kj::TaskSet m_on_disconnect{m_error_handler};
492 ::capnp::TwoPartyVatNetwork m_network;
493 std::optional<::capnp::RpcSystem<::capnp::rpc::twoparty::VatId>> m_rpc_system;
494
495 // ThreadMap interface client, used to create a remote server thread when an
496 // client IPC call is being made for the first time from a new thread.
497 ThreadMap::Client m_thread_map{nullptr};
498
501 ::capnp::CapabilityServerSet<Thread> m_threads;
502
504 struct PoolSlot {
505 Thread::Client client;
506 size_t depth{0};
507 };
508 std::vector<PoolSlot> m_thread_pool;
509
513 kj::Canceler m_canceler;
514
519};
520
530{
531 ::capnp::word scratch[4]{};
532 ::capnp::MallocMessageBuilder message{scratch};
533 ::capnp::rpc::twoparty::VatId::Builder vat_id{message.getRoot<::capnp::rpc::twoparty::VatId>()};
534 ServerVatId() { vat_id.setSide(::capnp::rpc::twoparty::Side::SERVER); }
535};
536
537template <typename Interface, typename Impl>
539 Connection* connection,
541 : m_client(std::move(client)), m_context(connection)
542
543{
544 MP_LOG(*m_context.loop, Log::Debug) << "Creating " << CxxTypeName(*this) << " " << this;
545 // Handler for the connection getting destroyed before this client object.
547 // Release client capability by move-assigning to temporary.
548 {
549 typename Interface::Client(std::move(m_client));
550 }
551 Lock lock{m_context.loop->m_mutex};
552 m_context.connection = nullptr;
553 });
554
555 // Two shutdown sequences are supported:
556 //
557 // - A normal sequence where client proxy objects are deleted by external
558 // code that no longer needs them
559 //
560 // - A garbage collection sequence where the connection or event loop shuts
561 // down while external code is still holding client references.
562 //
563 // The first case is handled here when m_context.connection is not null. The
564 // second case is handled by the disconnect_cb function, which sets
565 // m_context.connection to null so nothing happens here.
567 {
568 // If the capnp interface defines a destroy method, call it to destroy
569 // the remote object, waiting for it to be deleted server side. If the
570 // capnp interface does not define a destroy method, this will just call
571 // an empty stub defined in the ProxyClientBase class and do nothing.
572 // Exceptions are caught and logged rather than propagated because
573 // ~ProxyClientBase is noexcept and the peer may be gone by the time
574 // this runs.
575 if (kj::runCatchingExceptions([&]{ Sub::destroy(*this); }) != nullptr) {
576 MP_LOG(*m_context.loop, Log::Warning) << "Remote destroy call failed during cleanup. Continuing.";
577 }
578
579 // FIXME: Could just invoke removed addCleanup fn here instead of duplicating code
580 m_context.loop->sync([&]() {
581 // Remove disconnect callback on cleanup so it doesn't run and try
582 // to access this object after it's destroyed. This call needs to
583 // run inside loop->sync() on the event loop thread because
584 // otherwise, if there were an ill-timed disconnect, the
585 // onDisconnect handler could fire and delete the Connection object
586 // before the removeSyncCleanup call.
588
589 // Release client capability by move-assigning to temporary.
590 {
591 typename Interface::Client(std::move(m_client));
592 }
593 if (destroy_connection) {
594 delete m_context.connection;
595 m_context.connection = nullptr;
596 }
597 });
598 }
599 });
600 // If construct() fails, run the cleanup functions before rethrowing,
601 // because ~ProxyClientBase will not run for an object whose constructor
602 // threw, and the connection would otherwise be leaked.
603 try {
604 Sub::construct(*this);
605 } catch (...) {
606 MP_LOG(*m_context.loop, Log::Debug) << "Cleaning up " << CxxTypeName(*this) << " " << this << " after construct() failure";
608 throw;
609 }
610
611 // If this client owns the connection, delete the connection on disconnect.
612 if (destroy_connection) {
613 m_context.loop->sync([&] {
614 EventLoop& loop = *m_context.loop;
615 Connection* connection = m_context.connection;
616 connection->onDisconnect([&loop, connection] {
617 MP_LOG(loop, Log::Warning) << "IPC client: unexpected network disconnect.";
618 delete connection;
619 });
620 });
621 }
622}
623
624template <typename Interface, typename Impl>
626{
627 MP_LOG(*m_context.loop, Log::Debug) << "Cleaning up " << CxxTypeName(*this) << " " << this;
628 CleanupRun(m_context.cleanup_fns);
629 MP_LOG(*m_context.loop, Log::Debug) << "Destroying " << CxxTypeName(*this) << " " << this;
630}
631
632template <typename Interface, typename Impl>
633ProxyServerBase<Interface, Impl>::ProxyServerBase(std::shared_ptr<Impl> impl, Connection& connection)
634 : m_impl(std::move(impl)), m_context(&connection)
635{
636 MP_LOG(*m_context.loop, Log::Debug) << "Creating " << CxxTypeName(*this) << " " << this;
637 assert(m_impl);
638}
639
652template <typename Interface, typename Impl>
654{
655 MP_LOG(*m_context.loop, Log::Debug) << "Cleaning up " << CxxTypeName(*this) << " " << this;
656 if (m_impl) {
657 // If impl is non-null at this point, it means no client is waiting for
658 // the m_impl server object to be destroyed synchronously. This can
659 // happen either if the interface did not define a "destroy" method (see
660 // invokeDestroy method below), or if a destroy method was defined, but
661 // the connection was broken before it could be called.
662 //
663 // In either case, be conservative and run the cleanup on an
664 // asynchronous thread, to avoid destructors or cleanup functions
665 // blocking or deadlocking the current EventLoop thread, since they
666 // could be making IPC calls.
667 //
668 // Technically this is a little too conservative since if the interface
669 // defines a "destroy" method, but the destroy method does not accept a
670 // Context parameter specifying a worker thread, the cleanup method
671 // would run on the EventLoop thread normally (when connection is
672 // unbroken), but will not run on the EventLoop thread now (when
673 // connection is broken). Probably some refactoring of the destructor
674 // and invokeDestroy function is possible to make this cleaner and more
675 // consistent.
676 m_context.loop->addAsyncCleanup([impl=std::move(m_impl), fns=std::move(m_context.cleanup_fns)]() mutable {
677 impl.reset();
678 CleanupRun(fns);
679 });
680 }
681 assert(m_context.cleanup_fns.empty());
682 MP_LOG(*m_context.loop, Log::Debug) << "Destroying " << CxxTypeName(*this) << " " << this;
683}
684
702template <typename Interface, typename Impl>
704{
705 m_impl.reset();
706 CleanupRun(m_context.cleanup_fns);
707}
708
715using ConnThreads = std::map<Connection*, std::optional<ProxyClient<Thread>>>;
716using ConnThread = ConnThreads::iterator;
717
718// Retrieve ProxyClient<Thread> object associated with this connection from a
719// map, or create a new one and insert it into the map. Return map iterator and
720// inserted bool.
721std::tuple<ConnThread, bool> SetThread(GuardedRef<ConnThreads> threads, Connection* connection, const std::function<Thread::Client()>& make_thread);
722
737{
739 std::string thread_name;
740
756 std::unique_ptr<Waiter> waiter = nullptr;
757
776
787
791 bool loop_thread = false;
792};
793
794template<typename T, typename Fn>
795kj::Promise<T> ProxyServer<Thread>::post(Fn&& fn)
796{
797 auto ready = kj::newPromiseAndFulfiller<void>(); // Signaled when waiter is ready to post again.
798 auto cancel_monitor_ptr = kj::heap<CancelMonitor>();
800 // Keep a reference to the ProxyServer<Thread> instance by assigning it to
801 // the self variable. ProxyServer instances are reference-counted and if the
802 // client drops its reference, this variable keeps the instance alive until
803 // the thread finishes executing. The self variable needs to be destroyed on
804 // the event loop thread so it is freed in a sync() call below.
805 auto self = thisCap();
806 auto ret = m_thread_ready.then([this, self = std::move(self), fn = std::forward<Fn>(fn), ready_fulfiller = kj::mv(ready.fulfiller), cancel_monitor_ptr = kj::mv(cancel_monitor_ptr)]() mutable {
807 auto result = kj::newPromiseAndFulfiller<T>(); // Signaled when fn() is called, with its return value.
808 bool posted = m_thread_context.waiter->post([this, self = std::move(self), fn = std::forward<Fn>(fn), ready_fulfiller = kj::mv(ready_fulfiller), result_fulfiller = kj::mv(result.fulfiller), cancel_monitor_ptr = kj::mv(cancel_monitor_ptr)]() mutable {
809 // Fulfill ready.promise now, as soon as the Waiter starts executing
810 // this lambda, so the next ProxyServer<Thread>::post() call can
811 // immediately call waiter->post(). It is important to do this
812 // before calling fn() because fn() can make an IPC call back to the
813 // client, which can make another IPC call to this server thread.
814 // (This typically happens when IPC methods take std::function
815 // parameters.) When this happens the second call to the server
816 // thread should not be blocked waiting for the first call.
817 m_loop->sync([ready_fulfiller = kj::mv(ready_fulfiller)]() mutable {
818 ready_fulfiller->fulfill();
819 ready_fulfiller = nullptr;
820 });
821 std::optional<T> result_value;
822 kj::Maybe<kj::Exception> exception{kj::runCatchingExceptions([&]{ result_value.emplace(fn(*cancel_monitor_ptr)); })};
823 m_loop->sync([this, &result_value, &exception, self = kj::mv(self), result_fulfiller = kj::mv(result_fulfiller), cancel_monitor_ptr = kj::mv(cancel_monitor_ptr)]() mutable {
824 // Destroy CancelMonitor here before fulfilling or rejecting the
825 // promise so it doesn't get triggered when the promise is
826 // destroyed.
827 cancel_monitor_ptr = nullptr;
828 // Send results to the fulfiller. Technically it would be ok to
829 // skip this if promise was canceled, but it's simpler to just
830 // do it unconditionally.
831 KJ_IF_MAYBE(e, exception) {
832 assert(!result_value);
833 result_fulfiller->reject(kj::mv(*e));
834 } else {
835 assert(result_value);
836 result_fulfiller->fulfill(kj::mv(*result_value));
837 result_value.reset();
838 }
839 result_fulfiller = nullptr;
840 // Use evalLater to destroy the ProxyServer<Thread> self
841 // reference, if it is the last reference, because the
842 // ProxyServer<Thread> destructor needs to join the thread,
843 // which can't happen until this sync() block has exited.
844 m_loop->m_task_set->add(kj::evalLater([self = kj::mv(self)] {}));
845 });
846 });
847 // Assert that calling Waiter::post did not fail. It could only return
848 // false if a new function was posted before the previous one finished
849 // executing, but new functions are only posted when m_thread_ready is
850 // signaled, so this should never happen.
851 assert(posted);
852 return kj::mv(result.promise);
853 }).attach(kj::heap<CancelProbe>(cancel_monitor));
854 m_thread_ready = kj::mv(ready.promise);
855 return ret;
856}
857
870template <typename InitInterface>
871std::unique_ptr<ProxyClient<InitInterface>> ConnectStream(EventLoop& loop, Stream stream, bool destroy_connection = true)
872{
873 typename InitInterface::Client init_client(nullptr);
874 std::unique_ptr<Connection> connection;
875 loop.sync([&] {
876 connection = std::make_unique<Connection>(loop, kj::mv(stream));
877 init_client = connection->m_rpc_system->bootstrap(ServerVatId().vat_id).castAs<InitInterface>();
878 });
879 return std::make_unique<ProxyClient<InitInterface>>(kj::mv(init_client), connection.release(), destroy_connection);
880}
881
893template <typename InitInterface, typename InitImpl, typename OnDisconnect>
894std::pair<ProxyServer<InitInterface>*, EventLoop::Connections::iterator> _Serve(EventLoop& loop,
895 kj::Own<kj::AsyncIoStream>&& stream,
896 std::shared_ptr<InitImpl> init,
898 bool destroy_connection = true)
899{
900 ProxyServer<InitInterface>* server = nullptr;
901 loop.m_incoming_connections.emplace_front(loop, kj::mv(stream), [&](Connection& connection) {
902 auto proxy_server = kj::heap<ProxyServer<InitInterface>>(std::move(init), connection);
903 server = proxy_server;
904 return capnp::Capability::Client(kj::mv(proxy_server));
905 });
906 auto it = loop.m_incoming_connections.begin();
907 MP_LOG(loop, Log::Info) << "IPC server: socket connected.";
909 it->onDisconnect([&loop, it, on_disconnect = std::forward<OnDisconnect>(on_disconnect), destroy_connection]() mutable {
910 MP_LOG(loop, Log::Info) << "IPC server: socket disconnected.";
911 if (destroy_connection) loop.m_incoming_connections.erase(it);
914 });
915 return {server, it};
916}
917
927template <typename InitInterface, typename InitImpl, typename OnDisconnect>
928std::pair<ProxyServer<InitInterface>*, EventLoop::Connections::iterator> _Serve(EventLoop& loop,
929 kj::Own<kj::AsyncIoStream>&& stream,
930 InitImpl& init,
932 bool destroy_connection = true)
933{
934 return _Serve<InitInterface>(loop, kj::mv(stream), std::shared_ptr<InitImpl>(&init, [](InitImpl*){}),
935 std::forward<OnDisconnect>(on_disconnect), destroy_connection);
936}
937
939{
940 explicit Listener(kj::Own<kj::ConnectionReceiver>&& receiver, std::optional<size_t> max_connections)
941 : m_receiver(kj::mv(receiver)), m_max_connections(max_connections) {}
942
943 bool atCapacity() const
944 {
946 }
947
948 kj::Own<kj::ConnectionReceiver> m_receiver;
949 std::optional<size_t> m_max_connections;
951};
952
953template <typename InitInterface, typename InitImpl>
954void _Listen(const std::shared_ptr<Listener>& listener, EventLoop& loop, InitImpl& init)
955{
956 if (listener->atCapacity()) return;
957
958 auto* receiver = listener->m_receiver.get();
959 loop.m_task_set->add(receiver->accept().then(
960 [&loop, &init, listener](kj::Own<kj::AsyncIoStream>&& stream) {
961 ++listener->m_active_connections;
962 _Serve<InitInterface>(loop, kj::mv(stream), init, [&loop, &init, listener] {
963 const bool resume_accept{listener->atCapacity()};
964 assert(listener->m_active_connections > 0);
965 --listener->m_active_connections;
966 if (resume_accept) _Listen<InitInterface>(listener, loop, init);
967 });
969 }));
970}
971
975template <typename InitInterface, typename InitImpl>
976std::pair<ProxyServer<InitInterface>*, EventLoop::Connections::iterator> ServeStream(
977 EventLoop& loop, Stream stream, InitImpl&& init, bool destroy_connection = true)
978{
979 return _Serve<InitInterface>(loop, kj::mv(stream), std::forward<InitImpl>(init), /*on_disconnect=*/ [] {}, destroy_connection);
980}
981
984template <typename InitInterface, typename InitImpl>
985void ListenConnections(EventLoop& loop, SocketId fd, InitImpl& init, std::optional<size_t> max_connections = std::nullopt)
986{
987 loop.sync([&]() {
988 auto listener{std::make_shared<Listener>(
989 loop.m_io_context.lowLevelProvider->wrapListenSocketFd(fd, kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP),
990 max_connections)};
992 });
993}
994
995extern thread_local ThreadContext g_thread_context; // NOLINT(bitcoin-nontrivial-threadlocal)
996// Silence nonstandard bitcoin tidy error "Variable with non-trivial destructor
997// cannot be thread_local" which should not be a problem on modern platforms, and
998// could lead to a small memory leak at worst on older ones.
999
1018ThreadContext& CurrentThread();
1019
1020} // namespace mp
1021
1022#endif // MP_PROXY_IO_H
int ret
int flags
Helper class that detects when a promise is canceled.
Definition util.h:369
Object holding network & rpc state associated with either an incoming server connection,...
Definition proxy-io.h:446
CleanupIt addSyncCleanup(std::function< void()> fn)
Register synchronous cleanup function to run on event loop thread (with access to capnp thread local ...
Definition proxy.cpp:211
EventLoopRef m_loop
Definition proxy-io.h:485
::capnp::TwoPartyVatNetwork m_network
Definition proxy-io.h:492
kj::Own< kj::AsyncIoStream > m_stream
Definition proxy-io.h:486
Connection(EventLoop &loop, kj::Own< kj::AsyncIoStream > &&stream_, const std::function<::capnp::Capability::Client(Connection &)> &make_client)
Definition proxy-io.h:452
Connection(EventLoop &loop, kj::Own< kj::AsyncIoStream > &&stream_)
Definition proxy-io.h:448
void onDisconnect(F &&f)
Add disconnect handler.
Definition proxy-io.h:474
std::vector< PoolSlot > m_thread_pool
Definition proxy-io.h:508
kj::Canceler m_canceler
Canceler for canceling promises that we want to discard when the connection is destroyed.
Definition proxy-io.h:513
::capnp::CapabilityServerSet< Thread > m_threads
Collection of server-side IPC worker threads (ProxyServer<Thread> objects previously returned by Thre...
Definition proxy-io.h:501
CleanupList m_sync_cleanup_fns
Cleanup functions to run if connection is broken unexpectedly.
Definition proxy-io.h:518
std::optional<::capnp::RpcSystem<::capnp::rpc::twoparty::VatId > > m_rpc_system
Definition proxy-io.h:493
void removeSyncCleanup(CleanupIt it)
Definition proxy.cpp:225
Event loop implementation.
Definition proxy-io.h:248
const char * m_exe_name
Process name included in thread names so combined debug output from multiple processes is easier to u...
Definition proxy-io.h:302
kj::AsyncIoContext m_io_context
Capnp IO context.
Definition proxy-io.h:338
Connections m_incoming_connections
List of connections.
Definition proxy-io.h:347
std::condition_variable m_cv
Definition proxy-io.h:335
EventLoop(const char *exe_name, LogFn log_fn, void *context=nullptr)
Construct event loop object with default logging options.
Definition proxy-io.h:251
kj::FunctionParam< void()> *m_sync_fn MP_GUARDED_BY(m_mutex)
Callback function to run on event loop thread during sync() call.
std::function< void()> testing_hook_connected
Hook called on the event loop thread when a client has connected.
Definition proxy-io.h:372
void sync(kj::FunctionParam< void()> fn)
Run function on event loop thread.
Definition proxy.cpp:336
Mutex m_mutex
Mutex and condition variable used to post tasks to event loop and async thread.
Definition proxy-io.h:334
int m_num_refs MP_GUARDED_BY(m_mutex)=0
Number of EventLoopRef instances referencing this event loop.
kj::Own< kj::AsyncIoStream > m_post_stream
Definition proxy-io.h:319
std::list< Connection > Connections
Type of m_incoming_connections list.
Definition proxy-io.h:295
std::function< void()> testing_hook_disconnected
Hook called on the event loop thread when a client has disconnected.
Definition proxy-io.h:375
LogOptions m_log_opts
Logging options.
Definition proxy-io.h:350
std::unique_ptr< kj::TaskSet > m_task_set
Capnp list of pending promises.
Definition proxy-io.h:344
void * m_context
External context pointer.
Definition proxy-io.h:353
std::function< void()> testing_hook_makethread
Hook called when ProxyServer<ThreadMap>::makeThread() is called.
Definition proxy-io.h:356
std::optional< CleanupList > m_async_fns MP_GUARDED_BY(m_mutex)
Callback functions to run on async thread.
kj::Own< kj::OutputStream > m_post_writer
Synchronous writer used to write to m_post_stream.
Definition proxy-io.h:322
std::thread m_async_thread
Handle of an async worker thread.
Definition proxy-io.h:309
std::function< void()> testing_hook_makethread_created
Hook called on the worker thread inside makeThread(), after the thread context is set up and thread_c...
Definition proxy-io.h:361
EventLoop(const char *exe_name, std::function< void(bool, std::string)> old_callback, void *context=nullptr)
Backwards-compatible constructor for previous (deprecated) logging callback signature.
Definition proxy-io.h:258
kj::Own< kj::AsyncIoStream > m_wait_stream
Socket pair used to post and wait for wakeups to the event loop thread.
Definition proxy-io.h:318
std::function< void()> testing_hook_async_request_done
Hook called on the worker thread just before returning results.
Definition proxy-io.h:369
std::function< void()> testing_hook_async_request_start
Hook called on the worker thread when it starts to execute an async request.
Definition proxy-io.h:366
std::function< void(std::any)> testing_hook_misc
Miscellaneous testing hook.
Definition proxy-io.h:381
Event loop smart pointer automatically managing m_num_refs.
Definition proxy.h:53
friend Logger & operator<<(Logger &logger, T &&value)
Definition proxy-io.h:185
Logger(const Logger &)=delete
bool enabled() const
Definition proxy-io.h:203
~Logger() noexcept(false)
Definition proxy-io.h:179
Logger & operator=(Logger &&)=delete
Log m_log_level
Definition proxy-io.h:209
Logger(Logger &&)=delete
Logger(const LogOptions &options, Log log_level)
Definition proxy-io.h:172
const LogOptions & m_options
Definition proxy-io.h:208
friend Logger & operator<<(Logger &&logger, T &&value)
Definition proxy-io.h:192
std::ostringstream m_buffer
Definition proxy-io.h:210
Logger & operator=(const Logger &)=delete
Handler for kj::TaskSet failed task events.
Definition proxy-io.h:125
LoggingErrorHandler(EventLoop &loop)
Definition proxy-io.h:127
void taskFailed(kj::Exception &&exception) override
Definition proxy.cpp:59
Base class for generated ProxyClient classes that implement a C++ interface and forward calls to a ca...
Definition proxy.h:83
Interface::Client m_client
Definition proxy.h:134
ProxyContext m_context
Definition proxy.h:135
~ProxyClientBase() noexcept
Definition proxy-io.h:625
ProxyClientBase(typename Interface::Client client, Connection *connection, bool destroy_connection)
Construct libmultiprocess client object wrapping Cap'n Proto client object with a reference to the as...
Definition proxy-io.h:538
#define T(expected, seed, data)
std::optional< mp::EventLoop > m_loop
EventLoop object which manages I/O events for all connections.
Definition protocol.cpp:150
Context m_context
Definition protocol.cpp:148
#define MP_REQUIRES(x)
Definition util.h:193
std::unique_ptr< ProxyClient< messages::FooInterface > > client
UnixListener listener
std::thread thread
Thread variable should be after other struct members so the thread does not start until the other mem...
Definition basic.cpp:11
Functions to serialize / deserialize common bitcoin types.
void Unlock(Lock &lock, Callback &&callback)
Definition util.h:244
std::string CxxTypeName(const T &)
Definition util.h:344
Stream MakeStream(EventLoop &loop, SocketId socket)
Wrap a socket file descriptor as an async stream, taking ownership of the fd.
Definition proxy.cpp:50
std::pair< ProxyServer< InitInterface > *, EventLoop::Connections::iterator > _Serve(EventLoop &loop, kj::Own< kj::AsyncIoStream > &&stream, std::shared_ptr< InitImpl > init, OnDisconnect &&on_disconnect, bool destroy_connection=true)
Given stream and init objects, construct a new ProxyServer object that handles requests from the stre...
Definition proxy-io.h:894
kj::StringPtr KJ_STRINGIFY(Log flags)
Definition proxy.cpp:531
kj::Own< kj::AsyncIoStream > Stream
Definition util.h:292
ThreadContext & CurrentThread()
Return the current thread's ThreadContext.
Definition proxy.cpp:45
std::list< std::function< void()> > CleanupList
Definition proxy.h:36
std::function< void(LogMessage)> LogFn
Definition proxy-io.h:153
int SocketId
Definition util.h:295
std::tuple< ConnThread, bool > SetThread(GuardedRef< ConnThreads > threads, Connection *connection, const std::function< Thread::Client()> &make_thread)
Definition proxy.cpp:386
thread_local ThreadContext g_thread_context
Definition proxy.cpp:43
std::pair< ProxyServer< InitInterface > *, EventLoop::Connections::iterator > ServeStream(EventLoop &loop, Stream stream, InitImpl &&init, bool destroy_connection=true)
Given a stream and an init object, handle requests on the stream by calling methods on the Init objec...
Definition proxy-io.h:976
void ListenConnections(EventLoop &loop, SocketId fd, InitImpl &init, std::optional< size_t > max_connections=std::nullopt)
Given listening socket identifier and an init object, handle incoming connections and requests by cal...
Definition proxy-io.h:985
Log
Log flags. Update stringify function if changed!
Definition proxy-io.h:133
std::string LongThreadName(const char *exe_name)
Definition proxy.cpp:526
ConnThreads::iterator ConnThread
Definition proxy-io.h:716
typename CleanupList::iterator CleanupIt
Definition proxy.h:37
void CleanupRun(CleanupList &fns)
Definition proxy.h:39
std::unique_ptr< ProxyClient< InitInterface > > ConnectStream(EventLoop &loop, Stream stream, bool destroy_connection=true)
Given a stream, make a new ProxyClient object to send requests over it.
Definition proxy-io.h:871
void _Listen(const std::shared_ptr< Listener > &listener, EventLoop &loop, InitImpl &init)
Definition proxy-io.h:954
std::map< Connection *, std::optional< ProxyClient< Thread > > > ConnThreads
Map from Connection to local or remote thread handle which will be used over that connection.
Definition proxy-io.h:715
#define MP_LOG(loop,...)
Definition proxy-io.h:215
ThreadContext & thread_context
Definition proxy-io.h:42
ClientInvokeContext(Connection &conn, ThreadContext &thread_context)
Definition proxy-io.h:43
A thread created by makePool with associated pending work queue. Vector is filled once by makePool() ...
Definition proxy-io.h:504
Thread::Client client
Definition proxy-io.h:505
Connection & connection
Definition proxy-io.h:37
std::optional< size_t > m_max_connections
Definition proxy-io.h:949
size_t m_active_connections
Definition proxy-io.h:950
kj::Own< kj::ConnectionReceiver > m_receiver
Definition proxy-io.h:948
Listener(kj::Own< kj::ConnectionReceiver > &&receiver, std::optional< size_t > max_connections)
Definition proxy-io.h:940
bool atCapacity() const
Definition proxy-io.h:943
Log level
The severity level of this message.
Definition proxy-io.h:150
std::string message
Message to be logged.
Definition proxy-io.h:147
LogFn log_fn
External logging callback.
Definition proxy-io.h:158
size_t max_chars
Maximum number of characters to use when representing request and response structs as strings.
Definition proxy-io.h:162
Log log_level
Messages with a severity level less than log_level will not be reported.
Definition proxy-io.h:166
ProxyClient(const ProxyClient &)=delete
std::optional< CleanupIt > m_disconnect_cb
Reference to callback function that is run if there is a sudden disconnect and the Connection object ...
Definition proxy-io.h:97
Mapping from capnp interface type to proxy client implementation (specializations are generated by pr...
Definition proxy.h:25
EventLoopRef loop
Definition proxy.h:73
Connection * connection
Definition proxy.h:72
CleanupList cleanup_fns
Definition proxy.h:74
ThreadContext & m_thread_context
Definition proxy-io.h:116
ProxyServerBase(std::shared_ptr< Impl > impl, Connection &connection)
Definition proxy-io.h:633
ProxyContext m_context
Definition proxy.h:174
void invokeDestroy()
If the capnp interface defined a special "destroy" method, as described the ProxyClientBase class,...
Definition proxy-io.h:703
virtual ~ProxyServerBase()
ProxyServer destructor, called from the EventLoop thread by Cap'n Proto garbage collection code after...
Definition proxy-io.h:653
std::shared_ptr< Impl > m_impl
Implementation pointer that may or may not be owned and deleted when this capnp server goes out of sc...
Definition proxy.h:173
Mapping from capnp interface type to proxy server implementation (specializations are generated by pr...
Definition proxy.h:28
CallContext_ CallContext
Definition proxy-io.h:52
ServerInvokeContext(ProxyServer &proxy_server, CallContext &call_context, int req)
Definition proxy-io.h:71
CallContext & call_context
Definition proxy-io.h:55
ProxyServer & proxy_server
Definition proxy-io.h:54
bool request_canceled
For IPC methods that execute asynchronously, not on the event-loop thread, this is set to true if the...
Definition proxy-io.h:69
Lock * cancel_lock
For IPC methods that execute asynchronously, not on the event-loop thread: lock preventing the event-...
Definition proxy-io.h:62
Vat id for server side of connection.
Definition proxy-io.h:530
The thread_local ThreadContext struct (see CurrentThread()) provides information about individual thr...
Definition proxy-io.h:737
ConnThreads callback_threads MP_GUARDED_BY(waiter->m_mutex)
When client is making a request to a server, this is the callbackThread argument it passes in the req...
std::unique_ptr< Waiter > waiter
Waiter object used to allow remote clients to execute code on this thread.
Definition proxy-io.h:756
ConnThreads request_threads MP_GUARDED_BY(waiter->m_mutex)
When client is making a request to a server, this is the thread argument it passes in the request,...
bool loop_thread
Whether this thread is a capnp event loop thread.
Definition proxy-io.h:791
std::string thread_name
Identifying string for debug.
Definition proxy-io.h:739
Single element task queue used to handle recursive capnp calls.
Definition proxy-io.h:396
void wait(Lock &lock, Predicate pred) MP_REQUIRES(m_mutex)
Definition proxy-io.h:410
Mutex m_mutex
Mutex mainly used internally by waiter class, but also used externally to guard access to related sta...
Definition proxy-io.h:435
std::optional< kj::Function< void()> > m_fn MP_GUARDED_BY(m_mutex)
std::condition_variable m_cv MP_GUARDED_BY(m_mutex)
bool post(Fn &&fn)
Definition proxy-io.h:400
Waiter()=default
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
assert(!tx.IsCoinBase())
WalletContext context