Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
proxy.cpp
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#include <mp/proxy.h>
6
7#include <mp/proxy-io.h>
8#include <mp/proxy-types.h>
9#include <mp/proxy.capnp.h>
10#include <mp/type-threadmap.h>
11#include <mp/util.h>
12
13#include <atomic>
14#include <capnp/capability.h>
15#include <capnp/common.h> // IWYU pragma: keep
16#include <capnp/rpc.h>
17#include <condition_variable>
18#include <functional>
19#include <future>
20#include <kj/async.h>
21#include <kj/async-io.h>
22#include <kj/async-prelude.h>
23#include <kj/common.h>
24#include <kj/debug.h>
25#include <kj/exception.h>
26#include <kj/function.h>
27#include <kj/io.h>
28#include <kj/memory.h>
29#include <kj/string.h>
30#include <cstdint>
31#include <map>
32#include <memory>
33#include <optional>
34#include <stdexcept>
35#include <string>
36#include <thread>
37#include <tuple>
38#include <utility>
39#include <vector>
40
41namespace mp {
42
43thread_local ThreadContext g_thread_context; // NOLINT(bitcoin-nontrivial-threadlocal)
44
49
51{
53 loop.sync([&]() {
54 stream = loop.m_io_context.lowLevelProvider->wrapSocketFd(socket, kj::LowLevelAsyncIoProvider::TAKE_OWNERSHIP);
55 });
56 return stream;
57}
58
59void LoggingErrorHandler::taskFailed(kj::Exception&& exception)
60{
61 KJ_LOG(ERROR, "Uncaught exception in daemonized task.", exception);
62 MP_LOG(m_loop, Log::Error) << "Uncaught exception in daemonized task.";
63}
64
65EventLoopRef::EventLoopRef(EventLoop& loop, Lock* lock) : m_loop(&loop), m_lock(lock)
66{
68 loop_lock->assert_locked(m_loop->m_mutex);
69 m_loop->m_num_refs += 1;
70}
71
72// Due to the conditionals in this function, MP_NO_TSA is required to avoid
73// error "error: mutex 'loop_lock' is not held on every path through here
74// [-Wthread-safety-analysis]"
76{
77 if (auto* loop{m_loop}) {
78 m_loop = nullptr;
79 auto loop_lock{PtrOrValue{m_lock, loop->m_mutex}};
80 loop_lock->assert_locked(loop->m_mutex);
81 assert(loop->m_num_refs > 0);
82 loop->m_num_refs -= 1;
83 if (loop->done()) {
84 loop->m_cv.notify_all();
85 // Capture loop->m_post_writer pointer before releasing the lock.
86 // The pointer can't actually change before the write() call below,
87 // but copying it with the lock held instead of accessing it
88 // directly below prevents TSAN false positives because TSAN is
89 // unaware of socketpair write() synchronization and might falsely
90 // report the pointer being used in this thread and assigned in the
91 // other thread without synchronization between.
92 kj::OutputStream* post_writer{loop->m_post_writer.get()};
93 loop_lock->unlock();
94 char buffer = 0;
95 // It safe to access post_writer here because the loop can't
96 // exit until this write takes place. See "Intentionally do not
97 // break..." comment in EventLoop::loop
98 post_writer->write(&buffer, 1);
99 // By default, do not try to relock `loop_lock` after writing,
100 // because the event loop could wake up and destroy itself and the
101 // mutex might no longer exist.
102 if (relock) loop_lock->lock();
103 }
104 }
105}
106
107ProxyContext::ProxyContext(Connection* connection) : connection(connection), loop{*connection->m_loop} {}
108
110{
111 // Connection destructor is always called on the event loop thread. If this
112 // is a local disconnect, it will trigger I/O, so this needs to run on the
113 // event loop thread, and if there was a remote disconnect, this is called
114 // by an onDisconnect callback directly from the event loop thread.
115 assert(std::this_thread::get_id() == m_loop->m_thread_id);
116
117 // Try to cancel any calls that may be executing.
118 m_canceler.cancel("Interrupted by disconnect");
119
120 // Shut down RPC system first, since this will garbage collect any
121 // ProxyServer objects that were not freed before the connection was closed.
122 // Typically all ProxyServer objects associated with this connection will be
123 // freed before this call returns. However that will not be the case if
124 // there are asynchronous IPC calls over this connection still currently
125 // executing. In that case, Cap'n Proto will destroy the ProxyServer objects
126 // after the calls finish.
127 m_rpc_system.reset();
128
129 // shutdownWrite is needed on Windows so pending data in the m_stream socket
130 // will be sent instead of discarded when m_stream is destroyed. On unix,
131 // this doesn't seem to be needed because data is sent more reliably.
132 //
133 // Sending pending data is important if the connection is a socketpair
134 // because when one side of the socketpair is closed, the other side doesn't
135 // seem to receive any onDisconnect event. So it is important for the other
136 // side to instead receive Cap'n Proto "release" messages (see `struct
137 // Release` in capnp/rpc.capnp) from local Client objects being destroyed so
138 // the remote side can free resources and shut down cleanly. Without this,
139 // when one side of a socket pair is closed the other side may not receive
140 // these messages, preventing the remote side from freeing ProxyServer
141 // resources and shutting down cleanly.
142 // Use kj::runCatchingExceptions instead of try/catch because on macOS with
143 // dynamic libraries, kj::Exception typeinfo differs between libcapnp and
144 // the calling binary, so catch (const kj::Exception&) silently fails to
145 // match. kj::runCatchingExceptions uses KJ's own interception mechanism
146 // which works correctly across dynamic library boundaries.
147 KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() {
148 m_stream->shutdownWrite();
149 })) {
150 // Ignore ENOTCONN: on macOS/FreeBSD (unlike Linux), shutdown(SHUT_WR)
151 // returns ENOTCONN if the peer already closed the connection. This is
152 // expected when the destructor is triggered by a remote disconnect.
153 // Also ignore UNIMPLEMENTED: shutdownWrite() may not be supported on
154 // all stream types (e.g. streams that do not support half-close).
155 if (exception->getType() != kj::Exception::Type::DISCONNECTED &&
156 exception->getType() != kj::Exception::Type::UNIMPLEMENTED) {
157 kj::throwRecoverableException(kj::mv(*exception));
158 }
159 }
160
161 // ProxyClient cleanup handlers are in sync list, and ProxyServer cleanup
162 // handlers are in the async list.
163 //
164 // The ProxyClient cleanup handlers are synchronous because they are fast
165 // and don't do anything besides release capnp resources and reset state so
166 // future calls to client methods immediately throw exceptions instead of
167 // trying to communicate across the socket. The synchronous callbacks set
168 // ProxyClient capability pointers to null, so new method calls on client
169 // objects fail without triggering i/o or relying on event loop which may go
170 // out of scope or trigger obscure capnp i/o errors.
171 //
172 // The ProxyServer cleanup handlers call user defined destructors on the server
173 // object, which can run arbitrary blocking bitcoin code so they have to run
174 // asynchronously in a different thread. The asynchronous cleanup functions
175 // intentionally aren't started until after the synchronous cleanup
176 // functions run, so client objects are fully disconnected before bitcoin
177 // code in the destructors are run. This way if the bitcoin code tries to
178 // make client requests the requests will just fail immediately instead of
179 // sending i/o or accessing the event loop.
180 //
181 // The context where Connection objects are destroyed and this destructor is invoked
182 // is different depending on whether this is an outgoing connection being used
183 // to make an Init.makeX call() (e.g. Init.makeNode or Init.makeWalletClient) or an incoming
184 // connection implementing the Init interface and handling the Init.makeX() calls.
185 //
186 // Either way when a connection is closed, capnp behavior is to call all
187 // ProxyServer object destructors first, and then trigger an onDisconnect
188 // callback.
189 //
190 // On incoming side of the connection, the onDisconnect callback is written
191 // to delete the Connection object from the m_incoming_connections and call
192 // this destructor which calls Connection::disconnect.
193 //
194 // On the outgoing side, the Connection object is owned by top level client
195 // object client, which onDisconnect handler doesn't have ready access to,
196 // so onDisconnect handler just calls Connection::disconnect directly
197 // instead.
198 //
199 // Either way disconnect code runs in the event loop thread and called both
200 // on clean and unclean shutdowns. In unclean shutdown case when the
201 // connection is broken, sync and async cleanup lists will be filled with
202 // callbacks. In the clean shutdown case both lists will be empty.
203 Lock lock{m_loop->m_mutex};
204 while (!m_sync_cleanup_fns.empty()) {
205 CleanupList fn;
206 fn.splice(fn.begin(), m_sync_cleanup_fns, m_sync_cleanup_fns.begin());
207 Unlock(lock, fn.front());
208 }
209}
210
211CleanupIt Connection::addSyncCleanup(std::function<void()> fn)
212{
213 const Lock lock(m_loop->m_mutex);
214 // Add cleanup callbacks to the front of list, so sync cleanup functions run
215 // in LIFO order. This is a good approach because sync cleanup functions are
216 // added as client objects are created, and it is natural to clean up
217 // objects in the reverse order they were created. In practice, however,
218 // order should not be significant because the cleanup callbacks run
219 // synchronously in a single batch when the connection is broken, and they
220 // only reset the connection pointers in the client objects without actually
221 // deleting the client objects.
222 return m_sync_cleanup_fns.emplace(m_sync_cleanup_fns.begin(), std::move(fn));
223}
224
226{
227 // Require cleanup functions to be removed on the event loop thread to avoid
228 // needing to deal with them being removed in the middle of a disconnect.
229 assert(std::this_thread::get_id() == m_loop->m_thread_id);
230 const Lock lock(m_loop->m_mutex);
231 m_sync_cleanup_fns.erase(it);
232}
233
234void EventLoop::addAsyncCleanup(std::function<void()> fn)
235{
236 const Lock lock(m_mutex);
237 // Add async cleanup callbacks to the back of the list. Unlike the sync
238 // cleanup list, this list order is more significant because it determines
239 // the order server objects are destroyed when there is a sudden disconnect,
240 // and it is possible objects may need to be destroyed in a certain order.
241 // This function is called in ProxyServerBase destructors, and since capnp
242 // destroys ProxyServer objects in LIFO order, we should preserve this
243 // order, and add cleanup callbacks to the end of the list so they can be
244 // run starting from the beginning of the list.
245 //
246 // In bitcoin core, running these callbacks in the right order is
247 // particularly important for the wallet process, because it uses blocking
248 // shared_ptrs and requires Chain::Notification pointers owned by the node
249 // process to be destroyed before the WalletLoader objects owned by the node
250 // process, otherwise shared pointer counts of the CWallet objects (which
251 // inherit from Chain::Notification) will not be 1 when WalletLoader
252 // destructor runs and it will wait forever for them to be released.
253 m_async_fns->emplace_back(std::move(fn));
255}
256
259 m_io_context(kj::setupAsyncIo()),
260 m_task_set(new kj::TaskSet(m_error_handler)),
261 m_log_opts(std::move(log_opts)),
263{
264 auto pipe = m_io_context.provider->newTwoWayPipe();
265 m_wait_stream = kj::mv(pipe.ends[0]);
266 m_post_stream = kj::mv(pipe.ends[1]);
267 KJ_IF_MAYBE(fd, m_post_stream->getFd()) {
268 m_post_writer = kj::heap<kj::FdOutputStream>(*fd);
269 } else {
270 throw std::logic_error("Could not get file descriptor for new pipe.");
271 }
272}
273
275{
276 if (m_async_thread.joinable()) m_async_thread.join();
277 const Lock lock(m_mutex);
278 KJ_ASSERT(m_sync_fn == nullptr);
282 KJ_ASSERT(m_num_refs == 0);
283
284 // Spin event loop. wait for any promises triggered by RPC shutdown.
285 // auto cleanup = kj::evalLater([]{});
286 // cleanup.wait(m_io_context.waitScope);
287}
288
290{
291 assert(!CurrentThread().loop_thread);
292 CurrentThread().loop_thread = true;
293 KJ_DEFER(CurrentThread().loop_thread = false);
294
295 {
296 const Lock lock(m_mutex);
298 m_async_fns.emplace();
299 }
300
301 kj::Own<kj::AsyncIoStream>& wait_stream{m_wait_stream};
302 char buffer = 0;
303 for (;;) {
304 const size_t read_bytes = wait_stream->read(&buffer, 0, 1).wait(m_io_context.waitScope);
305 if (read_bytes != 1) throw std::logic_error("EventLoop wait_stream closed unexpectedly");
306 Lock lock(m_mutex);
307 if (m_sync_fn) {
308 // m_sync_fn throwing is never expected. If it does happen, the caller
309 // of EventLoop::sync() will return without any indication of failure,
310 // which will likely cause other bugs. Log the error and continue.
311 KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]() MP_REQUIRES(m_mutex) { Unlock(lock, *m_sync_fn); })) {
312 MP_LOG(*this, Log::Error) << "EventLoop: m_sync_fn threw: " << kj::str(*exception).cStr();
313 }
314 m_sync_fn = nullptr;
315 m_cv.notify_all();
316 } else if (done()) {
317 // Intentionally do not break if m_sync_fn was set, even if done()
318 // would return true, to ensure that the sync() m_post_writer->write()
319 // call always succeeds and the loop does not exit between the time
320 // that the done condition is set and the write call is made.
321 break;
322 }
323 }
324 MP_LOG(*this, Log::Info) << "EventLoop::loop done, cancelling event listeners.";
325 m_task_set.reset();
326 MP_LOG(*this, Log::Info) << "EventLoop::loop bye.";
327 wait_stream = nullptr;
328 const Lock lock(m_mutex);
329 m_post_writer = nullptr;
330 m_wait_stream = nullptr;
331 m_post_stream = nullptr;
332 m_async_fns.reset();
333 m_cv.notify_all();
334}
335
336void EventLoop::sync(kj::FunctionParam<void()> fn)
337{
338 if (std::this_thread::get_id() == m_thread_id) {
339 fn();
340 return;
341 }
342 Lock lock(m_mutex);
343 EventLoopRef ref(*this, &lock);
344 m_cv.wait(lock.m_lock, [this]() MP_REQUIRES(m_mutex) { return m_sync_fn == nullptr; });
345 m_sync_fn = &fn;
346 Unlock(lock, [&] {
347 char buffer = 0;
348 m_post_writer->write(&buffer, 1);
349 });
350 m_cv.wait(lock.m_lock, [this, &fn]() MP_REQUIRES(m_mutex) { return m_sync_fn != &fn; });
351}
352
354{
355 assert (std::this_thread::get_id() == m_thread_id);
356 if (m_async_thread.joinable()) {
357 // Notify to wake up the async thread if it is already running.
358 m_cv.notify_all();
359 } else if (!m_async_fns->empty()) {
360 m_async_thread = std::thread([this] {
361 SetOsThreadName("capnp-async");
362 Lock lock(m_mutex);
363 while (m_async_fns) {
364 if (!m_async_fns->empty()) {
365 EventLoopRef ref{*this, &lock};
366 const std::function<void()> fn = std::move(m_async_fns->front());
367 m_async_fns->pop_front();
368 Unlock(lock, fn);
369 // Important to relock because of the wait() call below.
370 ref.reset(/*relock=*/true);
371 // Continue without waiting in case there are more async_fns
372 continue;
373 }
374 m_cv.wait(lock.m_lock);
375 }
376 });
377 }
378}
379
380bool EventLoop::done() const
381{
382 assert(m_num_refs >= 0);
383 return m_num_refs == 0 && m_async_fns->empty();
384}
385
386std::tuple<ConnThread, bool> SetThread(GuardedRef<ConnThreads> threads, Connection* connection, const std::function<Thread::Client()>& make_thread)
387{
388 assert(std::this_thread::get_id() == connection->m_loop->m_thread_id);
390 bool inserted;
391 {
392 const Lock lock(threads.mutex);
393 std::tie(thread, inserted) = threads.ref.try_emplace(connection);
394 }
395 if (inserted) {
396 thread->second.emplace(make_thread(), connection, /* destroy_connection= */ false);
397 thread->second->m_disconnect_cb = connection->addSyncCleanup([threads, thread] {
398 // Note: it is safe to use the `thread` iterator in this cleanup
399 // function, because the iterator would only be invalid if the map entry
400 // was removed, and if the map entry is removed the ProxyClient<Thread>
401 // destructor unregisters the cleanup.
402
403 // Connection is being destroyed before thread client is, so reset
404 // thread client m_disconnect_cb member so thread client destructor does not
405 // try to unregister this callback after connection is destroyed.
406 thread->second->m_disconnect_cb.reset();
407
408 // Remove connection pointer about to be destroyed from the map
409 const Lock lock(threads.mutex);
410 threads.ref.erase(thread);
411 });
412 }
413 return {thread, inserted};
414}
415
417{
418 // If thread is being destroyed before connection is destroyed, remove the
419 // cleanup callback that was registered to handle the connection being
420 // destroyed before the thread being destroyed.
421 if (m_disconnect_cb) {
422 // Remove disconnect callback on the event loop thread with
423 // loop->sync(), so if the connection is broken there is not a race
424 // between this thread trying to remove the callback and the disconnect
425 // handler attempting to call it.
426 m_context.loop->sync([&]() {
427 if (m_disconnect_cb) {
428 m_context.connection->removeSyncCleanup(*m_disconnect_cb);
429 }
430 });
431 }
432}
433
434ProxyServer<Thread>::ProxyServer(Connection& connection, ThreadContext& thread_context, std::thread&& thread)
435 : m_loop{*connection.m_loop}, m_thread_context(thread_context), m_thread(std::move(thread))
436{
437 assert(m_thread_context.waiter.get() != nullptr);
438}
439
441{
442 if (!m_thread.joinable()) return;
443 // Stop async thread and wait for it to exit. Need to wait because the
444 // m_thread handle needs to outlive the thread to avoid "terminate called
445 // without an active exception" error. An alternative to waiting would be
446 // detach the thread, but this would introduce nondeterminism which could
447 // make code harder to debug or extend.
448 assert(m_thread_context.waiter.get());
449 std::unique_ptr<Waiter> waiter;
450 {
451 const Lock lock(m_thread_context.waiter->m_mutex);
454 waiter = std::move(m_thread_context.waiter);
456 assert(!waiter->m_fn);
457 // Clear client maps now to avoid deadlock in m_thread.join() call
458 // below. The maps contain Thread::Client objects that need to be
459 // destroyed from the event loop thread (this thread), which can't
460 // happen if this thread is busy calling join.
461 m_thread_context.request_threads.clear();
462 m_thread_context.callback_threads.clear();
464 waiter->m_cv.notify_all();
465 }
466 m_thread.join();
467}
468
470{
471 context.getResults().setResult(m_thread_context.thread_name);
472 return kj::READY_NOW;
473}
474
476
478{
479 if (!m_connection.m_thread_pool.empty()) {
480 throw std::runtime_error("makePool called on connection with existing pool");
481 }
482 EventLoop& loop{*m_connection.m_loop};
483 const uint32_t count = context.getParams().getCount();
484 for (uint32_t i = 0; i < count; ++i) {
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]() {
488 SetOsThreadName(("capnp-pool-" + std::to_string(i)).c_str());
489 CurrentThread().thread_name = ThreadName(loop.m_exe_name) + " (" + thread_name + ")";
490 CurrentThread().waiter = std::make_unique<Waiter>();
491 Lock lock(CurrentThread().waiter->m_mutex);
492 thread_context.set_value(&CurrentThread());
493 CurrentThread().waiter->wait(lock, [] { return !CurrentThread().waiter; });
494 });
495 auto thread_server = kj::heap<ProxyServer<Thread>>(m_connection, *thread_context.get_future().get(), std::move(thread));
496 m_connection.m_thread_pool.push_back({m_connection.m_threads.add(kj::mv(thread_server))});
497 }
498 return kj::READY_NOW;
499}
500
502{
503 EventLoop& loop{*m_connection.m_loop};
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]() {
508 SetOsThreadName("capnp-worker");
509 CurrentThread().thread_name = ThreadName(loop.m_exe_name) + " (from " + from + ")";
510 CurrentThread().waiter = std::make_unique<Waiter>();
511 Lock lock(CurrentThread().waiter->m_mutex);
512 thread_context.set_value(&CurrentThread());
513 if (loop.testing_hook_makethread_created) loop.testing_hook_makethread_created();
514 // Wait for shutdown signal from ProxyServer<Thread> destructor (signal
515 // is just waiter getting set to null.)
516 CurrentThread().waiter->wait(lock, [] { return !CurrentThread().waiter; });
517 });
518 auto thread_server = kj::heap<ProxyServer<Thread>>(m_connection, *thread_context.get_future().get(), std::move(thread));
519 auto thread_client = m_connection.m_threads.add(kj::mv(thread_server));
520 context.getResults().setResult(kj::mv(thread_client));
521 return kj::READY_NOW;
522}
523
524std::atomic<int> server_reqs{0};
525
526std::string LongThreadName(const char* exe_name)
527{
529}
530
531kj::StringPtr KJ_STRINGIFY(Log v)
532{
533 switch (v) {
534 case Log::Trace: return "Trace";
535 case Log::Debug: return "Debug";
536 case Log::Info: return "Info";
537 case Log::Warning: return "Warning";
538 case Log::Error: return "Error";
539 case Log::Raise: return "Raise";
540 }
541 return "<Log?>";
542}
543} // namespace mp
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
kj::Own< kj::AsyncIoStream > m_stream
Definition proxy-io.h:486
kj::Canceler m_canceler
Canceler for canceling promises that we want to discard when the connection is destroyed.
Definition proxy-io.h:513
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
~Connection() noexcept(false)
Run cleanup functions.
Definition proxy.cpp:109
void removeSyncCleanup(CleanupIt it)
Definition proxy.cpp:225
Event loop implementation.
Definition proxy-io.h:248
kj::AsyncIoContext m_io_context
Capnp IO context.
Definition proxy-io.h:338
void startAsyncThread() MP_REQUIRES(m_mutex)
Start asynchronous worker thread if necessary.
Definition proxy.cpp:353
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
void addAsyncCleanup(std::function< void()> fn)
Register cleanup function to run on asynchronous worker thread without blocking the event loop thread...
Definition proxy.cpp:234
void loop()
Run event loop.
Definition proxy.cpp:289
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
bool done() const MP_REQUIRES(m_mutex)
Check if loop should exit.
Definition proxy.cpp:380
kj::Own< kj::AsyncIoStream > m_post_stream
Definition proxy-io.h:319
std::unique_ptr< kj::TaskSet > m_task_set
Capnp list of pending promises.
Definition proxy-io.h:344
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::thread::id m_thread_id
ID of the event loop thread.
Definition proxy-io.h:305
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
Event loop smart pointer automatically managing m_num_refs.
Definition proxy.h:53
EventLoopRef(EventLoop &loop, Lock *lock=nullptr)
Definition proxy.cpp:65
void reset(bool relock=false)
Definition proxy.cpp:75
EventLoop * m_loop
Definition proxy.h:65
Lock * m_lock
Definition proxy.h:66
std::unique_lock< std::mutex > m_lock
Definition util.h:220
void taskFailed(kj::Exception &&exception) override
Definition proxy.cpp:59
btcsignals::scoped_connection m_connection
const char * m_exe_name
Definition protocol.cpp:147
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_NO_TSA
Definition util.h:198
#define MP_REQUIRES(x)
Definition util.h:193
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)
Definition util.h:244
Stream MakeStream(EventLoop &loop, SocketId socket)
Wrap a socket file descriptor as an async stream, taking ownership of the fd.
Definition proxy.cpp:50
kj::StringPtr KJ_STRINGIFY(Log flags)
Definition proxy.cpp:531
void SetOsThreadName(const char *name)
Set the OS-level name of the current thread.
Definition util.cpp:180
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::string ThreadName(const char *exe_name)
Format current thread name as "{exe_name}-{$pid}/{thread_name}-{$tid}".
Definition util.cpp:197
std::atomic< int > server_reqs
Definition proxy.cpp:524
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
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
#define MP_LOG(loop,...)
Definition proxy-io.h:215
Mapping from capnp interface type to proxy client implementation (specializations are generated by pr...
Definition proxy.h:25
ProxyContext(Connection *connection)
Definition proxy.cpp:107
Mapping from capnp interface type to proxy server implementation (specializations are generated by pr...
Definition proxy.h:28
Convenient wrapper around std::variant<T*, T>
Definition util.h:169
The thread_local ThreadContext struct (see CurrentThread()) provides information about individual thr...
Definition proxy-io.h:737
std::unique_ptr< Waiter > waiter
Waiter object used to allow remote clients to execute code on this thread.
Definition proxy-io.h:756
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
static int count
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
assert(!tx.IsCoinBase())
WalletContext context