9#include <mp/proxy.capnp.h>
14#include <capnp/capability.h>
15#include <capnp/common.h>
17#include <condition_variable>
21#include <kj/async-io.h>
22#include <kj/async-prelude.h>
25#include <kj/exception.h>
26#include <kj/function.h>
61 KJ_LOG(
ERROR,
"Uncaught exception in daemonized task.", exception);
81 assert(loop->m_num_refs > 0);
82 loop->m_num_refs -= 1;
84 loop->m_cv.notify_all();
92 kj::OutputStream*
post_writer{loop->m_post_writer.get()};
118 m_canceler.cancel(
"Interrupted by disconnect");
147 KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() {
155 if (exception->getType() != kj::Exception::Type::DISCONNECTED &&
156 exception->getType() != kj::Exception::Type::UNIMPLEMENTED) {
157 kj::throwRecoverableException(kj::mv(*exception));
260 m_task_set(
new kj::TaskSet(m_error_handler)),
270 throw std::logic_error(
"Could not get file descriptor for new pipe.");
305 if (
read_bytes != 1)
throw std::logic_error(
"EventLoop wait_stream closed unexpectedly");
312 MP_LOG(*
this,
Log::Error) <<
"EventLoop: m_sync_fn threw: " << kj::str(*exception).cStr();
324 MP_LOG(*
this,
Log::Info) <<
"EventLoop::loop done, cancelling event listeners.";
406 thread->second->m_disconnect_cb.reset();
421 if (m_disconnect_cb) {
427 if (m_disconnect_cb) {
428 m_context.connection->removeSyncCleanup(*m_disconnect_cb);
437 assert(m_thread_context.waiter.get() !=
nullptr);
442 if (!m_thread.joinable())
return;
448 assert(m_thread_context.waiter.get());
449 std::unique_ptr<Waiter> waiter;
451 const Lock lock(m_thread_context.waiter->m_mutex);
454 waiter = std::move(m_thread_context.waiter);
461 m_thread_context.request_threads.clear();
462 m_thread_context.callback_threads.clear();
464 waiter->m_cv.notify_all();
471 context.getResults().setResult(m_thread_context.thread_name);
472 return kj::READY_NOW;
480 throw std::runtime_error(
"makePool called on connection with existing pool");
485 const std::string thread_name =
"pool/" + std::to_string(i);
486 std::promise<ThreadContext*> thread_context;
487 std::thread
thread([&loop, &thread_context, thread_name, i]() {
498 return kj::READY_NOW;
504 if (loop.testing_hook_makethread) loop.testing_hook_makethread();
505 const std::string from =
context.getParams().getName();
506 std::promise<ThreadContext*> thread_context;
507 std::thread
thread([&loop, &thread_context, from]() {
513 if (loop.testing_hook_makethread_created) loop.testing_hook_makethread_created();
521 return kj::READY_NOW;
Object holding network & rpc state associated with either an incoming server connection,...
CleanupIt addSyncCleanup(std::function< void()> fn)
Register synchronous cleanup function to run on event loop thread (with access to capnp thread local ...
kj::Own< kj::AsyncIoStream > m_stream
kj::Canceler m_canceler
Canceler for canceling promises that we want to discard when the connection is destroyed.
CleanupList m_sync_cleanup_fns
Cleanup functions to run if connection is broken unexpectedly.
std::optional<::capnp::RpcSystem<::capnp::rpc::twoparty::VatId > > m_rpc_system
~Connection() noexcept(false)
Run cleanup functions.
void removeSyncCleanup(CleanupIt it)
Event loop implementation.
kj::AsyncIoContext m_io_context
Capnp IO context.
void startAsyncThread() MP_REQUIRES(m_mutex)
Start asynchronous worker thread if necessary.
std::condition_variable m_cv
EventLoop(const char *exe_name, LogFn log_fn, void *context=nullptr)
Construct event loop object with default logging options.
void addAsyncCleanup(std::function< void()> fn)
Register cleanup function to run on asynchronous worker thread without blocking the event loop thread...
void loop()
Run event loop.
void sync(kj::FunctionParam< void()> fn)
Run function on event loop thread.
Mutex m_mutex
Mutex and condition variable used to post tasks to event loop and async thread.
bool done() const MP_REQUIRES(m_mutex)
Check if loop should exit.
kj::Own< kj::AsyncIoStream > m_post_stream
std::unique_ptr< kj::TaskSet > m_task_set
Capnp list of pending promises.
kj::Own< kj::OutputStream > m_post_writer
Synchronous writer used to write to m_post_stream.
std::thread m_async_thread
Handle of an async worker thread.
std::thread::id m_thread_id
ID of the event loop thread.
kj::Own< kj::AsyncIoStream > m_wait_stream
Socket pair used to post and wait for wakeups to the event loop thread.
Event loop smart pointer automatically managing m_num_refs.
EventLoopRef(EventLoop &loop, Lock *lock=nullptr)
void reset(bool relock=false)
std::unique_lock< std::mutex > m_lock
void taskFailed(kj::Exception &&exception) override
btcsignals::scoped_connection m_connection
std::optional< mp::EventLoop > m_loop
EventLoop object which manages I/O events for all connections.
std::thread thread
Thread variable should be after other struct members so the thread does not start until the other mem...
Functions to serialize / deserialize common bitcoin types.
void Unlock(Lock &lock, Callback &&callback)
Stream MakeStream(EventLoop &loop, SocketId socket)
Wrap a socket file descriptor as an async stream, taking ownership of the fd.
kj::StringPtr KJ_STRINGIFY(Log flags)
void SetOsThreadName(const char *name)
Set the OS-level name of the current thread.
kj::Own< kj::AsyncIoStream > Stream
ThreadContext & CurrentThread()
Return the current thread's ThreadContext.
std::list< std::function< void()> > CleanupList
std::string ThreadName(const char *exe_name)
Format current thread name as "{exe_name}-{$pid}/{thread_name}-{$tid}".
std::atomic< int > server_reqs
std::tuple< ConnThread, bool > SetThread(GuardedRef< ConnThreads > threads, Connection *connection, const std::function< Thread::Client()> &make_thread)
thread_local ThreadContext g_thread_context
Log
Log flags. Update stringify function if changed!
std::string LongThreadName(const char *exe_name)
ConnThreads::iterator ConnThread
typename CleanupList::iterator CleanupIt
Mapping from capnp interface type to proxy client implementation (specializations are generated by pr...
ProxyContext(Connection *connection)
Mapping from capnp interface type to proxy server implementation (specializations are generated by pr...
Convenient wrapper around std::variant<T*, T>
The thread_local ThreadContext struct (see CurrentThread()) provides information about individual thr...
std::unique_ptr< Waiter > waiter
Waiter object used to allow remote clients to execute code on this thread.
bool loop_thread
Whether this thread is a capnp event loop thread.
std::string thread_name
Identifying string for debug.
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.