bug: fix mptest hang, ProxyClient<Thread> deadlock in disconnect handler#201
Conversation
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
|
I captured two stack traces of mptest hang on master (1b8d4a6) to be more confident this PR fixes the bug. I might also be able to update the test to make it trigger this bug more reliably, but would need to think more about how to do that. Both stack traces were identical and showed a deadlock between
thread 1
#0 0x00007f480509438e in __futex_abstimed_wait_common () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6
#1 0x00007f4805097010 in pthread_cond_wait@@GLIBC_2.3.2 () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6
#2 0x000055df0ff8bdbb in std::condition_variable::wait<mp::EventLoop::post(kj::Function<void ()>)::$_2>(std::unique_lock<std::mutex>&, mp::EventLoop::post(kj::Function<void ()>)::$_2) (this=0x7f4804ffed08, __lock=..., __p=...)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/condition_variable:105
#3 mp::EventLoop::post (this=0x7f4804ffec90, fn=...) at mp/src/mp/proxy.cpp:273
269 Unlock(lock, [&] {
270 char buffer = 0;
271 KJ_SYSCALL(write(post_fd, &buffer, 1));
272 });
> 273 m_cv.wait(lock.m_lock, [this, &fn]() MP_REQUIRES(m_mutex) { return m_post_fn != &fn; });
274 }
#4 0x000055df0feefd7d in mp::EventLoop::sync<mp::ProxyClientBase<mp::test::messages::FooInterface, mp::test::FooImplementation>::ProxyClientBase(mp::test::messages::FooInterface::Client, mp::Connection*, bool)::{lambda()#2}::operator()() const::{lambda()#1}>(mp::ProxyClientBase<mp::test::messages::FooInterface, mp::test::FooImplementation>::ProxyClientBase(mp::test::messages::FooInterface::Client, mp::Connection*, bool)::{lambda()#2}::operator()() const::{lambda()#1}&&) (this=0x7f4804ffec90, callable=...) at mp/include/mp/proxy-io.h:182
179 template <typename Callable>
180 void sync(Callable&& callable)
181 {
> 182 post(std::forward<Callable>(callable));
183 }
#5 0x000055df0feefc52 in mp::ProxyClientBase<mp::test::messages::FooInterface, mp::test::FooImplementation>::ProxyClientBase(mp::test::messages::FooInterface::Client, mp::Connection*, bool)::{lambda()#2}::operator()() const (this=<optimized out>)
at mp/include/mp/proxy-io.h:434
431 Sub::destroy(*this);
432
433 // FIXME: Could just invoke removed addCleanup fn here instead of duplicating code
> 434 m_context.loop->sync([&]() {
435 // Remove disconnect callback on cleanup so it doesn't run and try
436 // to access this object after it's destroyed. This call needs to
437 // run inside loop->sync() on the event loop thread because
438 // otherwise, if there were an ill-timed disconnect, the
439 // onDisconnect handler could fire and delete the Connection object
440 // before the removeSyncCleanup call.
441 if (m_context.connection) m_context.connection->removeSyncCleanup(disconnect_cb);
#6 std::__invoke_impl<void, mp::ProxyClientBase<mp::test::messages::FooInterface, mp::test::FooImplementation>::ProxyClientBase(mp::test::messages::FooInterface::Client, mp::Connection*, bool)::{lambda()#2}&>(std::__invoke_other, mp::ProxyClientBase<mp::test::messages::FooInterface, mp::test::FooImplementation>::ProxyClientBase(mp::test::messages::FooInterface::Client, mp::Connection*, bool)::{lambda()#2}&) (__f=...) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/invoke.h:61
#7 std::__invoke_r<void, mp::ProxyClientBase<mp::test::messages::FooInterface, mp::test::FooImplementation>::ProxyClientBase(mp::test::messages::FooInterface::Client, mp::Connection*, bool)::{lambda()#2}&>(mp::ProxyClientBase<mp::test::messages::FooInterface, mp::test::FooImplementation>::ProxyClientBase(mp::test::messages::FooInterface::Client, mp::Connection*, bool)::{lambda()#2}&) (__fn=...) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/invoke.h:111
#8 std::_Function_handler<void (), mp::ProxyClientBase<mp::test::messages::FooInterface, mp::test::FooImplementation>::ProxyClientBase(mp::test::messages::FooInterface::Client, mp::Connection*, bool)::{lambda()#2}>::_M_invoke(std::_Any_data const&) (__functor=...)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/std_function.h:290
#9 0x000055df0ff52d26 in std::function<void()>::operator() (this=0x7fffb7c1b700) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/std_function.h:591
#10 mp::CleanupRun (fns=empty std::__cxx11::list) at mp/include/mp/proxy.h:43
39 inline void CleanupRun(CleanupList& fns) {
40 while (!fns.empty()) {
41 auto fn = std::move(fns.front());
42 fns.pop_front();
> 43 fn();
44 }
45 }
#11 0x000055df0ff872e7 in mp::ProxyClientBase<mp::test::messages::FooInterface, mp::test::FooImplementation>::~ProxyClientBase (this=0x7f4800027cf0) at mp/include/mp/proxy-io.h:460
457 template <typename Interface, typename Impl>
458 ProxyClientBase<Interface, Impl>::~ProxyClientBase() noexcept
459 {
> 460 CleanupRun(m_context.cleanup_fns);
461 }
#12 0x000055df0feebfc4 in std::default_delete<mp::ProxyClient<mp::test::messages::FooInterface> >::operator() (this=0x7fffb7c1b830, __ptr=0x7f4800027cf0) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/unique_ptr.h:93
#13 std::__uniq_ptr_impl<mp::ProxyClient<mp::test::messages::FooInterface>, std::default_delete<mp::ProxyClient<mp::test::messages::FooInterface> > >::reset (this=0x7fffb7c1b830, __p=0x0)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/unique_ptr.h:205
#14 std::unique_ptr<mp::ProxyClient<mp::test::messages::FooInterface>, std::default_delete<mp::ProxyClient<mp::test::messages::FooInterface> > >::reset (this=0x7fffb7c1b830, __p=0x0)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/unique_ptr.h:504
#15 mp::test::TestSetup::~TestSetup (this=this@entry=0x7fffb7c1b7d8) at mp/test/mp/test/test.cpp:103
98 ~TestSetup()
99 {
100 // Test that client cleanup_fns are executed.
101 bool destroyed = false;
102 client->m_context.cleanup_fns.emplace_front([&destroyed] { destroyed = true; });
> 103 client.reset();
104 KJ_EXPECT(destroyed);
105
106 thread.join();
107 }
#16 0x000055df0fee997f in mp::test::TestCase251::run (this=<optimized out>) at mp/test/mp/test/test.cpp:298
292 // Now that the disconnect has been detected, set signal allowing the
293 // callFnAsync() IPC call to return. Since signalling may not wake up the
294 // thread right away, it is important for the signal variable to be declared
295 // *before* the TestSetup variable so is not destroyed while
296 // signal.get_future().get() is called.
297 signal.set_value();
> 298 }
#17 0x00007f4805a34291 in kj::Maybe<kj::Exception> kj::runCatchingExceptions<kj::TestRunner::run()::{lambda()#1}>(kj::TestRunner::run()::{lambda()#1}&&) () from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj-test.so.1.1.0
#18 0x00007f4805a33a08 in kj::TestRunner::run() () from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj-test.so.1.1.0
#19 0x00007f4805a337bd in kj::Function<kj::MainBuilder::Validity ()>::Impl<kj::_::BoundMethod<kj::TestRunner&, kj::TestRunner::getMain()::{lambda(auto:1&, (auto:2&&)...)#7}, kj::TestRunner::getMain()::{lambda(auto:1&, (auto:2&&)...)#8}> >::operator()() ()
from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj-test.so.1.1.0
#20 0x00007f480572f93d in kj::MainBuilder::MainImpl::operator()(kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>) () from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj.so.1.1.0
#21 0x00007f480572df56 in kj::Maybe<kj::Exception> kj::runCatchingExceptions<kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**)::$_0>(kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**)::$_0&&) () from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj.so.1.1.0
#22 0x00007f480572dc7f in kj::runMainAndExit(kj::ProcessContext&, kj::Function<void (kj::StringPtr, kj::ArrayPtr<kj::StringPtr const>)>&&, int, char**) () from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj.so.1.1.0
#23 0x00007f4805a329b9 in main () from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj-test.so.1.1.0
#24 0x00007f480502a47e in __libc_start_call_main () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6
#25 0x00007f480502a539 in __libc_start_main_impl () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6
#26 0x000055df0fee6eb5 in _start ()
thread 2
#0 0x00007f480509438e in __futex_abstimed_wait_common () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6
#1 0x00007f4805097010 in pthread_cond_wait@@GLIBC_2.3.2 () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6
#2 0x000055df0ff8bd0b in std::condition_variable::wait<mp::EventLoop::post(kj::Function<void ()>)::$_0>(std::unique_lock<std::mutex>&, mp::EventLoop::post(kj::Function<void ()>)::$_0) (this=0x7f4804ffed08, __lock=..., __p=...)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/condition_variable:105
#3 mp::EventLoop::post (this=this@entry=0x7f4804ffec90, fn=...) at mp/src/mp/proxy.cpp:266
258 void EventLoop::post(kj::Function<void()> fn)
259 {
260 if (std::this_thread::get_id() == m_thread_id) {
261 fn();
262 return;
263 }
264 Lock lock(m_mutex);
265 EventLoopRef ref(*this, &lock);
> 266 m_cv.wait(lock.m_lock, [this]() MP_REQUIRES(m_mutex) { return m_post_fn == nullptr; });
267 m_post_fn = &fn;
268 int post_fd{m_post_fd};
269 Unlock(lock, [&] {
270 char buffer = 0;
271 KJ_SYSCALL(write(post_fd, &buffer, 1));
272 });
273 m_cv.wait(lock.m_lock, [this, &fn]() MP_REQUIRES(m_mutex) { return m_post_fn != &fn; });
274 }
#4 0x000055df0ff8f22d in mp::EventLoop::sync<mp::ProxyClientBase<mp::Thread, capnp::Void>::ProxyClientBase(mp::Thread::Client, mp::Connection*, bool)::{lambda()#2}::operator()() const::{lambda()#1}>(mp::ProxyClientBase<mp::Thread, capnp::Void>::ProxyClientBase(mp::Thread::Client, mp::Connection*, bool)::{lambda()#2}::operator()() const::{lambda()#1}&&) (this=0x7f4804ffec90, callable=...) at mp/include/mp/proxy-io.h:182
179 template <typename Callable>
180 void sync(Callable&& callable)
181 {
> 182 post(std::forward<Callable>(callable));
183 }
#5 0x000055df0ff8f102 in mp::ProxyClientBase<mp::Thread, capnp::Void>::ProxyClientBase(mp::Thread::Client, mp::Connection*, bool)::{lambda()#2}::operator()() const (this=<optimized out>) at mp/include/mp/proxy-io.h:434
431 Sub::destroy(*this);
432
433 // FIXME: Could just invoke removed addCleanup fn here instead of duplicating code
> 434 m_context.loop->sync([&]() {
435 // Remove disconnect callback on cleanup so it doesn't run and try
436 // to access this object after it's destroyed. This call needs to
437 // run inside loop->sync() on the event loop thread because
438 // otherwise, if there were an ill-timed disconnect, the
439 // onDisconnect handler could fire and delete the Connection object
440 // before the removeSyncCleanup call.
441 if (m_context.connection) m_context.connection->removeSyncCleanup(disconnect_cb);
#6 std::__invoke_impl<void, mp::ProxyClientBase<mp::Thread, capnp::Void>::ProxyClientBase(mp::Thread::Client, mp::Connection*, bool)::{lambda()#2}&>(std::__invoke_other, mp::ProxyClientBase<mp::Thread, capnp::Void>::ProxyClientBase(mp::Thread::Client, mp::Connection*, bool)::{lambda()#2}&) (__f=...) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/invoke.h:61
#7 std::__invoke_r<void, mp::ProxyClientBase<mp::Thread, capnp::Void>::ProxyClientBase(mp::Thread::Client, mp::Connection*, bool)::{lambda()#2}&>(mp::ProxyClientBase<mp::Thread, capnp::Void>::ProxyClientBase(mp::Thread::Client, mp::Connection*, bool)::{lambda()#2}&) (__fn=...)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/invoke.h:111
#8 std::_Function_handler<void (), mp::ProxyClientBase<mp::Thread, capnp::Void>::ProxyClientBase(mp::Thread::Client, mp::Connection*, bool)::{lambda()#2}>::_M_invoke(std::_Any_data const&) (__functor=...)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/std_function.h:290
#9 0x000055df0ff52d26 in std::function<void()>::operator() (this=0x7f47ffffe870) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/std_function.h:591
#10 mp::CleanupRun (fns=empty std::__cxx11::list) at mp/include/mp/proxy.h:43
39 inline void CleanupRun(CleanupList& fns) {
40 while (!fns.empty()) {
41 auto fn = std::move(fns.front());
42 fns.pop_front();
> 43 fn();
44 }
45 }
#11 0x000055df0ff8e627 in mp::ProxyClientBase<mp::Thread, capnp::Void>::~ProxyClientBase (this=0x7f47f8000e58) at mp/include/mp/proxy-io.h:460
457 template <typename Interface, typename Impl>
458 ProxyClientBase<Interface, Impl>::~ProxyClientBase() noexcept
459 {
> 460 CleanupRun(m_context.cleanup_fns);
461 }
#12 0x000055df0ff53129 in std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> >::~pair (this=0x7f47f8000e50) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/stl_iterator.h:3013
#13 std::destroy_at<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > (__location=0x7f47f8000e50) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/stl_construct.h:88
#14 std::allocator_traits<std::allocator<std::_Rb_tree_node<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > > >::destroy<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > (__p=0x7f47f8000e50, __a=...)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/alloc_traits.h:599
#15 std::_Rb_tree<mp::Connection*, std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> >, std::_Select1st<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > >, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >::_M_destroy_node (this=0x7f47fffff680, __p=0x7f47f8000e30) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/stl_tree.h:621
#16 std::_Rb_tree<mp::Connection*, std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> >, std::_Select1st<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > >, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >::_M_drop_node (this=0x7f47fffff680, __p=0x7f47f8000e30) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/stl_tree.h:629
#17 std::_Rb_tree<mp::Connection*, std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> >, std::_Select1st<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > >, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >::_M_erase (this=this@entry=0x7f47fffff680, __x=0x7f47f8000e30) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/stl_tree.h:1934
#18 0x000055df0ff530c9 in std::_Rb_tree<mp::Connection*, std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> >, std::_Select1st<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > >, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >::clear (this=0x7f47fffff680) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/stl_tree.h:1251
#19 std::_Rb_tree<mp::Connection*, std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> >, std::_Select1st<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > >, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >::_M_erase_aux (this=0x7f47fffff680, __first={...}, __last={...}) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/stl_tree.h:2505
#20 0x000055df0ff70fa6 in std::_Rb_tree<mp::Connection*, std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> >, std::_Select1st<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > >, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >::erase (this=0x7f4804ffed30, __x=<optimized out>) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/stl_tree.h:2519
#21 std::map<mp::Connection*, mp::ProxyClient<mp::Thread>, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >::erase (this=0x7f4804ffed30, __x=<optimized out>)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/stl_map.h:1118
#22 operator() (this=this@entry=0x7f47ffffeaf8) at mp/include/mp/type-context.h:103
102 const bool erase_thread{inserted};
103 KJ_DEFER(if (erase_thread) {
104 std::unique_lock<std::mutex> lock(thread_context.waiter->m_mutex);
105 // Call erase here with a Connection* argument instead
106 // of an iterator argument, because the `request_thread`
107 // iterator may be invalid if the connection is closed
108 // during this function call. More specifically, the
109 // iterator may be invalid because SetThread adds a
110 // cleanup callback to the Connection destructor that
111 // erases the thread from the map, and also because the
112 // ProxyServer<Thread> destructor calls
113 // request_threads.clear().
> 114 request_threads.erase(server.m_context.connection);
115 });
116 fn.invoke(server_context, args...);
117 }
#23 0x000055df0ff709c7 in run (this=<optimized out>) at /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/include/kj/common.h:2007
#24 ~Deferred (this=<optimized out>) at /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/include/kj/common.h:1996
#25 operator() (this=0x7f4800034628) at mp/include/mp/type-context.h:117
> 117 }
#26 0x000055df0ff04920 in kj::Function<void()>::operator() (this=0x7f47ffffeda0) at /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/include/kj/function.h:119
#27 mp::Unlock<std::unique_lock<std::mutex>, kj::Function<void()>&> (lock=..., callback=...) at mp/include/mp/util.h:198
194 template <typename Lock, typename Callback>
195 void Unlock(Lock& lock, Callback&& callback)
196 {
197 const UnlockGuard<Lock> unlock(lock);
> 198 callback();
199 }
#28 0x000055df0ff8d979 in mp::Waiter::wait<mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0::operator()() const::{lambda()#1}>(std::unique_lock<std::mutex>&, mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0::operator()() const::{lambda()#1})::{lambda()#1}::operator()() const (this=<optimized out>) at mp/include/mp/proxy-io.h:296
284 template <class Predicate>
285 void wait(std::unique_lock<std::mutex>& lock, Predicate pred)
286 {
287 m_cv.wait(lock, [&] {
288 // Important for this to be "while (m_fn)", not "if (m_fn)" to avoid
289 // a lost-wakeup bug. A new m_fn and m_cv notification might be sent
290 // after the fn() call and before the lock.lock() call in this loop
291 // in the case where a capnp response is sent and a brand new
292 // request is immediately received.
293 while (m_fn) {
294 auto fn = std::move(*m_fn);
295 m_fn.reset();
> 296 Unlock(lock, fn);
297 }
298 const bool done = pred();
299 return done;
300 });
301 }
#29 std::condition_variable::wait<mp::Waiter::wait<mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0::operator()() const::{lambda()#1}>(std::unique_lock<std::mutex>&, mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0::operator()() const::{lambda()#1})::{lambda()#1}>(std::unique_lock<std::mutex>&, mp::Waiter::wait<mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0::operator()() const::{lambda()#1}>(std::unique_lock<std::mutex>&, mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0::operator()() const::{lambda()#1})::{lambda()#1}) (this=0x7f47f8000dd8, __lock=..., __p=...) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/condition_variable:104
#30 mp::Waiter::wait<mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0::operator()() const::{lambda()#1}>(std::unique_lock<std::mutex>&, mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0::operator()() const::{lambda()#1}) (this=0x7f47f8000db0, lock=..., pred=...) at mp/include/mp/proxy-io.h:287
> 287 m_cv.wait(lock, [&] {
#31 mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0::operator()() const (this=<optimized out>) at mp/src/mp/proxy.cpp:404
393 kj::Promise<void> ProxyServer<ThreadMap>::makeThread(MakeThreadContext context)
394 {
395 const std::string from = context.getParams().getName();
396 std::promise<ThreadContext*> thread_context;
397 std::thread thread([&thread_context, from, this]() {
398 g_thread_context.thread_name = ThreadName(m_connection.m_loop->m_exe_name) + " (from " + from + ")";
399 g_thread_context.waiter = std::make_unique<Waiter>();
400 thread_context.set_value(&g_thread_context);
401 std::unique_lock<std::mutex> lock(g_thread_context.waiter->m_mutex);
402 // Wait for shutdown signal from ProxyServer<Thread> destructor (signal
403 // is just waiter getting set to null.)
> 404 g_thread_context.waiter->wait(lock, [] { return !g_thread_context.waiter; });
405 });
406 auto thread_server = kj::heap<ProxyServer<Thread>>(*thread_context.get_future().get(), std::move(thread));
407 auto thread_client = m_connection.m_threads.add(kj::mv(thread_server));
408 context.getResults().setResult(kj::mv(thread_client));
409 return kj::READY_NOW;
410 }
#32 std::__invoke_impl<void, mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0>(std::__invoke_other, mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0&&) (__f=...) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/invoke.h:61
#33 std::__invoke<mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0>(mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0&&) (__fn=...) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/invoke.h:96
#34 std::thread::_Invoker<std::tuple<mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0> >::_M_invoke<0ul> (this=<optimized out>)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/std_thread.h:301
#35 std::thread::_Invoker<std::tuple<mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0> >::operator() (this=<optimized out>)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/std_thread.h:308
#36 std::thread::_State_impl<std::thread::_Invoker<std::tuple<mp::ProxyServer<mp::ThreadMap>::makeThread(capnp::CallContext<mp::ThreadMap::MakeThreadParams, mp::ThreadMap::MakeThreadResults>)::$_0> > >::_M_run (this=<optimized out>)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/std_thread.h:253
#37 0x00007f48054ed064 in execute_native_thread_routine () from /nix/store/7c0v0kbrrdc2cqgisi78jdqxn73n3401-gcc-14.2.1.20250322-lib/lib/libstdc++.so.6
#38 0x00007f4805097e63 in start_thread () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6
#39 0x00007f480511bdbc in __clone3 () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6thread 3
#0 0x00007f480509463f in __lll_lock_wait () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6
#1 0x00007f480509b392 in pthread_mutex_lock@@GLIBC_2.2.5 () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6
#2 0x000055df0ff8d324 in __gthread_mutex_lock (__mutex=0x7f47f8000db0) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/x86_64-unknown-linux-gnu/bits/gthr-default.h:762
#3 std::mutex::lock (this=0x7f47f8000db0) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/std_mutex.h:113
#4 std::unique_lock<std::mutex>::lock (this=<optimized out>) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/unique_lock.h:147
#5 std::unique_lock<std::mutex>::unique_lock (__m=..., this=<optimized out>) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/unique_lock.h:73
#6 mp::SetThread(std::map<mp::Connection*, mp::ProxyClient<mp::Thread>, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >&, std::mutex&, mp::Connection*, std::function<mp::Thread::Client ()> const&)::$_0::operator()() const (
this=0x7f47f8001170) at mp/src/mp/proxy.cpp:326
308 std::tuple<ConnThread, bool> SetThread(ConnThreads& threads, std::mutex& mutex, Connection* connection, const std::function<Thread::Client()>& make_thread)
309 {
310 const std::unique_lock<std::mutex> lock(mutex);
311 auto thread = threads.find(connection);
312 if (thread != threads.end()) return {thread, false};
313 thread = threads.emplace(
314 std::piecewise_construct, std::forward_as_tuple(connection),
315 std::forward_as_tuple(make_thread(), connection, /* destroy_connection= */ false)).first;
316 thread->second.setDisconnectCallback([&threads, &mutex, thread] {
317 // Note: it is safe to use the `thread` iterator in this cleanup
318 // function, because the iterator would only be invalid if the map entry
319 // was removed, and if the map entry is removed the ProxyClient<Thread>
320 // destructor unregisters the cleanup.
321
322 // Connection is being destroyed before thread client is, so reset
323 // thread client m_disconnect_cb member so thread client destructor does not
324 // try to unregister this callback after connection is destroyed.
325 // Remove connection pointer about to be destroyed from the map
> 326 const std::unique_lock<std::mutex> lock(mutex);
327 thread->second.m_disconnect_cb.reset();
328 threads.erase(thread);
329 });
330 return {thread, true};
331 }
#7 std::__invoke_impl<void, mp::SetThread(std::map<mp::Connection*, mp::ProxyClient<mp::Thread>, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >&, std::mutex&, mp::Connection*, std::function<mp::Thread::Client ()> const&)::$_0&>(std::__invoke_other, mp::SetThread(std::map<mp::Connection*, mp::ProxyClient<mp::Thread>, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >&, std::mutex&, mp::Connection*, std::function<mp::Thread::Client ()> const&)::$_0&)
(__f=...) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/invoke.h:61
#8 std::__invoke_r<void, mp::SetThread(std::map<mp::Connection*, mp::ProxyClient<mp::Thread>, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >&, std::mutex&, mp::Connection*, std::function<mp::Thread::Client ()> const&)::$_0&>(mp::SetThread(std::map<mp::Connection*, mp::ProxyClient<mp::Thread>, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >&, std::mutex&, mp::Connection*, std::function<mp::Thread::Client ()> const&)::$_0&) (__fn=...)
at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/invoke.h:111
#9 std::_Function_handler<void(), mp::SetThread(std::map<mp::Connection*, mp::ProxyClient<mp::Thread>, std::less<mp::Connection*>, std::allocator<std::pair<mp::Connection* const, mp::ProxyClient<mp::Thread> > > >&, std::mutex&, mp::Connection*, std::function<mp::Thread::Client()> const&)::$_0>::_M_invoke (__functor=...) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/std_function.h:290
#10 0x000055df0ff8de15 in std::function<void()>::operator() (this=0x7f47f8000fb0) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/std_function.h:591
#11 mp::Unlock<mp::Lock, std::function<void()>&> (lock=..., callback=...) at mp/include/mp/util.h:198
194 template <typename Lock, typename Callback>
195 void Unlock(Lock& lock, Callback&& callback)
196 {
197 const UnlockGuard<Lock> unlock(lock);
> 198 callback();
199 }
#12 0x000055df0ff8a70f in mp::Connection::~Connection (this=0x7f480002a810) at mp/src/mp/proxy.cpp:139
135 Lock lock{m_loop->m_mutex};
136 while (!m_sync_cleanup_fns.empty()) {
137 CleanupList fn;
138 fn.splice(fn.begin(), m_sync_cleanup_fns, m_sync_cleanup_fns.begin());
> 139 Unlock(lock, fn.front());
140 }
141 }
#13 0x000055df0feeedd3 in std::default_delete<mp::Connection>::operator() (__ptr=0x7f480002a810, this=<optimized out>) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/unique_ptr.h:93
#14 std::__uniq_ptr_impl<mp::Connection, std::default_delete<mp::Connection> >::reset (this=0xfffffffffffffe00, __p=0x0) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/unique_ptr.h:205
#15 std::unique_ptr<mp::Connection, std::default_delete<mp::Connection> >::reset (this=0xfffffffffffffe00, __p=0x0) at /nix/store/9ds850ifd4jwcccpp3v14818kk74ldf2-gcc-14.2.1.20250322/include/c++/14.2.1.20250322/bits/unique_ptr.h:504
#16 mp::test::TestSetup::TestSetup(bool)::{lambda()#1}::operator()() const::{lambda()#2}::operator()() const (this=<optimized out>) at mp/test/mp/test/test.cpp:79
76 server_disconnect = [&] { loop.sync([&] { server_connection.reset(); }); };
77 // Set handler to destroy the server when the client disconnects. This
78 // is ignored if server_disconnect() is called instead.
> 79 server_connection->onDisconnect([&] { server_connection.reset(); });
80
81 auto client_connection = std::make_unique<Connection>(loop, kj::mv(pipe.ends[1]));
#17 kj::_::MaybeVoidCaller<kj::_::Void, kj::_::Void>::apply<mp::test::TestSetup::TestSetup(bool)::{lambda()#1}::operator()() const::{lambda()#2}>(mp::test::TestSetup::TestSetup(bool)::{lambda()#1}::operator()() const::{lambda()#2}&, kj::_::Void&&) (func=..., in=...)
at /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/include/kj/async-prelude.h:195
#18 kj::_::TransformPromiseNode<kj::_::Void, kj::_::Void, mp::test::TestSetup::TestSetup(bool)::{lambda()#1}::operator()() const::{lambda()#2}, kj::_::PropagateException>::getImpl(kj::_::ExceptionOrValue&) (this=<optimized out>, output=...)
at /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/include/kj/async-inl.h:739
#19 0x00007f48057c3a3e in kj::_::TransformPromiseNodeBase::get(kj::_::ExceptionOrValue&) () from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj-async.so.1.1.0
#20 0x00007f48057d102a in kj::TaskSet::Task::fire() () from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj-async.so.1.1.0
#21 0x00007f48057d143d in non-virtual thunk to kj::TaskSet::Task::fire() () from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj-async.so.1.1.0
#22 0x00007f48057c8cb2 in kj::_::waitImpl(kj::Own<kj::_::PromiseNode, kj::_::PromiseDisposer>&&, kj::_::ExceptionOrValue&, kj::WaitScope&, kj::SourceLocation)::$_2::operator()() const () from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj-async.so.1.1.0
#23 0x00007f48057c1d68 in kj::_::waitImpl(kj::Own<kj::_::PromiseNode, kj::_::PromiseDisposer>&&, kj::_::ExceptionOrValue&, kj::WaitScope&, kj::SourceLocation) () from /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/lib/libkj-async.so.1.1.0
#24 0x000055df0ff8e44c in kj::Promise<unsigned long>::wait (this=<optimized out>, waitScope=..., location=...) at /nix/store/46kiq9naswgbqfc14kc9nxcbgd0rv0m2-capnproto-1.1.0/include/kj/async-inl.h:1357
#25 0x000055df0ff8b722 in mp::EventLoop::loop (this=0x7f4804ffec90) at mp/src/mp/proxy.cpp:231
> 231 const size_t read_bytes = wait_stream->read(&buffer, 0, 1).wait(m_io_context.waitScope);
#26 0x000055df0feed376 in mp::test::TestSetup::TestSetup(bool)::{lambda()#1}::operator()() const (this=0x7f480002d1e8) at mp/test/mp/test/test.cpp:92
91 client_promise.set_value(std::move(client_proxy));
> 92 loop.loop();
#27 0x00007f48054ed064 in execute_native_thread_routine () from /nix/store/7c0v0kbrrdc2cqgisi78jdqxn73n3401-gcc-14.2.1.20250322-lib/lib/libstdc++.so.6
#28 0x00007f4805097e63 in start_thread () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6
#29 0x00007f480511bdbc in __clone3 () from /nix/store/cg9s562sa33k78m63njfn1rw47dp9z0i-glibc-2.40-66/lib/libc.so.6 |
fe1cbed to
1d6d854
Compare
|
Updated fe1cbed -> 1d6d854 ( |
Eunovo
left a comment
There was a problem hiding this comment.
TestedACK 1d6d854
As I understand it, there are two problems that are solved by this PR:
- a kind of use-after-free bug where the disconnect_cb is deleted in one thread while it is being executed in another
- a deadlock caused by two threads competing for the same waiter mutex
I left comments with more details under this review.
564e353 to
f219f1b
Compare
ryanofsky
left a comment
There was a problem hiding this comment.
Thanks for the review! Updated with suggested changes
re: #201 (review)
As I understand it, there are two problems that are solved by this PR:
Yes, there were basically the deadlock bug which happened most commonly, and different race bugs that could happen because there wasn't really any synchronization previously between disconnect handler and the type-context.h cleanup code after asynchronous IPC calls.
Updated 1d6d854 -> 564e353 (pr/context.2 -> pr/context.3, compare) updating comments and adding assert.
Updated 564e353 -> f219f1b (pr/context.3 -> pr/context.4, compare) fixing LLM linter issues
|
Can confirm that this fixes the observed test hang. |
|
utACK f219f1b I left some suggestions to make the intermediate commits more clear, which might benefit other reviewers. |
Use -Wthread-safety not -Wthread-safety-analysis in llvm and sanitize jobs. -Wthread-safety is a more general flag which adds additional checks outside the core thread safety analysis. Credit to hodlinator for noticing the bitcoin core build being stricter about thread safety checks than the libmultiprocess build here: bitcoin-core#201 (comment)
This is just a refactoring, no behavior is changing. This is only adding annotations and switching from unannotated to annotated types. In SetThread, the first two parameters are combined into a single GuardedRef parameter to avoid -Wthread-safety-reference warnings at call sites like "warning: passing variable 'callback_threads' by reference requires holding mutex 'thread_context.waiter->m_mutex'"
This is just a refactoring changing the ConnThreads data type. The optional value is not actually left in an unset state until the next commit.
This commit easiest to review ignoring whitespace (git diff -w). This is a minor change in behavior, but the only change is shortening the duration that threads.mutex is locked while inserting a new entry in the threads.ref map. The lock is now only held while the entry is created and is released while the ProxyClient<Thread> object is initialized. This change doesn't really fix any problems but it simplifies the next commit which deals with race conditions and deadlocks in this code, so it has been split out.
…returning This bug is currently causing mptest "disconnecting and blocking" test to occasionally hang as reported by maflcko in bitcoin/bitcoin#33244. The bug was actually first reported by Sjors in Sjors/bitcoin#90 (comment) and there are more details about it in bitcoin-core#189. The bug is caused by the "disconnecting and blocking" test triggering a disconnect right before a server IPC call returns. This results in a race between the IPC server thread and the onDisconnect handler in the event loop thread both trying to destroy the server's request_threads ProxyClient<Thread> object when the IPC call is done. There was a lack of synchronization in this case, fixed here by adding loop->sync() a few places. Specifically the fixes were to: - Always call SetThread on the event loop thread using the loop->sync() method, to prevent a race between the ProxyClient<Thread> creation code and the connection shutdown code if there was an ill-timed disconnect. - Similarly in ~ProxyClient<Thread> and thread-context.h PassField(), use loop->sync() when destroying the thread object, in case a disconnect happens at that time. A few other changes were made in this commit to make the resulting code safer and simpler, even though they are not technically necessary for the fix: - In thread-context.h PassField(), Waiter::m_mutex is now unlocked while destroying ProxyClient<Thread> just to respect EventLoop::m_mutex and Waiter::m_mutex lock order and never lock the Waiter first. This is just for consistency. There is no actually possibility for a deadlock here due to the new sync() call. - This adds asserts to make sure functions expected to run on the event loop thread are only called on that thread. - This inlines the ProxyClient<Thread>::setDisconnectCallback function, just because it was a short function only called in a single place.
f219f1b to
b6321bb
Compare
There was a problem hiding this comment.
Thanks for the reviews! I took Sjors commits to break the change up into smaller parts and addressed hodlinators suggestions to add more thread safety annotations and make them more strict. I think both changes should make this PR easier to review.
Updated f219f1b -> b6321bb (pr/context.4 -> pr/context.5, compare) with suggested changes to split commits and improve thread safety annotations. This actual fix is not changed.
Updated b6321bb -> d86823e (pr/context.5 -> pr/context.6, compare) fixing typos
b6321bb to
d86823e
Compare
|
Openbsd / clang-16 fix seems to have worked! |
|
ACK 4a269b2 |
|
I've made progress on implementing a more comprehensive disconnect test that can detect bugs like bitcoin/bitcoin#33244 and #189 more reliably instead of only intermittently when the test is run thousands of times. If I can finish it soon, I'll add it to this PR, otherwise it can be a followup. The test is implemented in commit ea4976f (tag) and I think I'm maybe 70% finished with the implementation. The test passes on master because not all of the checks are enabled yet and many aren't implemented (these are noted in FIXME comments in the code). The commit combines the 4 existing disconnect test cases into a more general test and follows up on earlier ideas and efforts from: |
|
@ryanofsky that commit also touches non-test code, so I think it would be better as a standalone PR. |
That's reasonable. But to be fair the only changes to non-test code are adding 4 lines like: if (connection->m_loop->m_signal) connection->m_loop->m_signal(SignalCallSetup{});so the test is able to disconnect at specific points. if (connection->m_loop->hasSignal<CallSetup>()) connection->m_loop->sendSignal<CallSetup>()); |
| CI_DIR=build-sanitize | ||
| export CXX=clang++ | ||
| export CXXFLAGS="-ggdb -Werror -Wall -Wextra -Wpedantic -Wthread-safety-analysis -Wno-unused-parameter -fsanitize=thread" | ||
| export CXXFLAGS="-ggdb -Werror -Wall -Wextra -Wpedantic -Wthread-safety -Wno-unused-parameter -fsanitize=thread" |
There was a problem hiding this comment.
4e365b0:
This is unrelated to the PR, but why generate debugging information here? I'm referring to the use of the -ggdb flag
There was a problem hiding this comment.
re: #201 (comment)
I haven't tried without -ggdb, but sanitizers like ThreadSanitizer print stack traces that I think depend on having this debug information. Cap'n Proto also can use addr2line to print stack traces internally when there are errors (though I don't think we have this option enabled)
| std::unique_ptr<Waiter> waiter; | ||
| { | ||
| const std::unique_lock<std::mutex> lock(m_thread_context.waiter->m_mutex); | ||
| const Lock lock(m_thread_context.waiter->m_mutex); |
There was a problem hiding this comment.
d60db60:
Clang's thread-safety analysis doesn't work inside destructors. It might not be worth the trouble to try to remedy the situation, but I'm just pointing it out
Use -Wthread-safety not -Wthread-safety-analysis in llvm and sanitize jobs. -Wthread-safety is a more general flag which adds additional checks outside the core thread safety analysis. Credit to hodlinator for noticing the bitcoin core build being stricter about thread safety checks than the libmultiprocess build here: bitcoin-core#201 (comment)
|
I think I'll go ahead and merge PR this since it's had acks and testing to confirm the fix works. I would have liked to add my test changes here to test it in a more reliable way but it's taking longer than expected to implement so better to make it a followup. |
…b8a552 47d79db8a552 Merge bitcoin-core/libmultiprocess#201: bug: fix mptest hang, ProxyClient<Thread> deadlock in disconnect handler f15ae9c9b9fb Merge bitcoin-core/libmultiprocess#211: Add .gitignore 4a269b21b8c8 bug: fix ProxyClient<Thread> deadlock if disconnected as IPC call is returning 85df96482c49 Use try_emplace in SetThread instead of threads.find ca9b380ea91a Use std::optional in ConnThreads to allow shortening locks 9b0799113557 doc: describe ThreadContext struct and synchronization requirements d60db601ed9b proxy-io.h: add Waiter::m_mutex thread safety annotations 4e365b019a9f ci: Use -Wthread-safety not -Wthread-safety-analysis 15d7bafbb001 Add .gitignore fe1cd8c76131 Merge bitcoin-core/libmultiprocess#208: ci: Test minimum cmake version in olddeps job b713a0b7bfbc Merge bitcoin-core/libmultiprocess#207: ci: output CMake version in CI script 0f580397c913 ci: Test minimum cmake version in olddeps job d603dcc0eef0 ci: output CMake version in CI script git-subtree-dir: src/ipc/libmultiprocess git-subtree-split: 47d79db8a5528097b408e18f7b0bae11a6702d26
hodlinator
left a comment
There was a problem hiding this comment.
Didn't fully get over the hump of knowing what I was looking at in the last commit before the merge this time. At least made me publish #213 (which originally contained a parallel discovery of #202).
Left some pending inline thoughts and the diagram below.
Tried diagramming out the example code to get a better grip on the library, but I'm not entirely friends with Mermaid.
---
config:
class:
hideEmptyMembersBox: true
---
classDiagram
class EventLoop{
+loop()
+sync()
+post()
}
class Waiter{
+post()
+wait()
}
class Connection {
+m_loop
+m_stream
+m_network
+m_rpc_system
+CleanupList m_sync_cleanup_fns
}
note for Connection "Server *or* Client"
class ProxyServer~Interface~
class ProxyClientBase~Interface, Impl~
note for ProxyClientBase "Inherits Impl"
class ProxyServerBase~Interface, Impl~ {
+shared_ptr~Impl~ m_impl
}
note for ProxyServerBase "Inherits Interface::Server,<br/>Owns Impl"
class Calculator {
+solveEquation(const std::string&) = 0
}
note for Calculator "Fairly typical pure virtual C++ interface"
class ProxyClient~::CalculatorInterface~ {
}
class ProxyClientCustom~::CalculatorInterface, Calculator~ {
}
class ProxyClientCustom~Interface, Impl~ {
}
ProxyClientCustom~::CalculatorInterface,Calculator~ <-- ProxyClient~::CalculatorInterface~
ProxyClientBase~Interface, Impl~ <-- ProxyClientCustom~Interface, Impl~
class TestSetup {
+thread
}
class TestSetup.thread {
+EventLoop
+pipe
+server_connection
+client_connection
+unique_ptr~ProxyClient~FooInterface~~ client_proxy
}
Connection "1" o-- "1" EventLoop
TestSetup "1" o-- "1" TestSetup.thread
TestSetup.thread "2" o-- "1" Connection : server & client
| std::unique_lock<std::mutex> m_lock; | ||
| }; | ||
|
|
||
| template<typename T> |
There was a problem hiding this comment.
meganit: Pretty sure Clang-format in main project prefers:
| template<typename T> | |
| template <typename T> |
There was a problem hiding this comment.
Tangent: Why does EventLoop use Unix sockets within the same process to signal when there's a new m_post_fn to execute? Seems like there should be thread synchronization primitives with marginally less overhead?
There was a problem hiding this comment.
re: https://github.com/bitcoin-core/libmultiprocess/pull/201/files#r2359060452
Tangent: Why does
EventLoopuse Unix sockets within the same process to signal when there's a newm_post_fnto execute? Seems like there should be thread synchronization primitives with marginally less overhead?
EventLoop documentation is meant to provide some background on this and specifically the link at the bottom https://groups.google.com/d/msg/capnproto/TuQFF1eH2-M/g81sHaTAAQAJ addresses this question.
Cap'n Proto doesn't use threads and assumes all code calling it runs on a single thread. There are benefits and costs that come from this but one of the costs is that external threads need to use I/O to communicate with cap'n proto's event loop. There isn't another way for threads to send signals. (Or at least there wasn't at time I wrote this, maybe newer versions of cap'n proto provide something)
There was a problem hiding this comment.
I think the main thing I was missing is the need for pumping the async IO. I assume waiting on a async IO-wrapped socket serves that purpose?
Was curious why you didn't use m_io_context->provider->newOneWayPipe() but when writing to the AsyncOutputStream a promise is returned with KJ_WARN_UNUSED_RESULT (https://github.com/capnproto/capnproto/blob/7db701e94ad00b8db06ede2bea5f527e2a6fa3de/c%2B%2B/src/kj/async-io.h#L121), which doesn't mirror what was in the example in Google Groups.
Q: I can see there's a ::close() call for [m_]post_fd, but none for m_wait_fd? Maybe it's garbage collected once the process dies, or does wrapSocketFd() assume responsibility for closing?
There was a problem hiding this comment.
re: #201 (comment)
Yes IIRC wrapSocketFd does take ownership. A lot of this code is also updated & made more generic in windows PR bitcoin/bitcoin#32387 in case you are curious.
There was a problem hiding this comment.
Tangent in unrelated file - regarding how easy it is to understand libmultiprocess:
TestSetup (in test/mp/test/test.cpp) is hard to read, maybe would benefit from adding comments with argument names of anonymous lambdas and explicit captures of variables. Also feeling resistance when having to learn that kj::heap returns something std::unique_ptr-like which implicit casts to raw pointer. Are the kj types only used when necessary to interface with Cap'n'Proto, and std everywhere else?
There was a problem hiding this comment.
re: #201 (comment)
Tangent in unrelated file - regarding how easy it is to understand libmultiprocess:
TestSetup(in test/mp/test/test.cpp) is hard to read, maybe would benefit from adding comments with argument names of anonymous lambdas and explicit captures of variables.
This is probably true and I'm currently working on test improvements where I'm adding more members to the TestSetup class and could add more comments.
I'm not sure I would always prefer explicit variable captures though. I think [&] is not just a way of capturing state and cutting down noise, but also an important way indicating that the lambda will only be called in the current scope, and is not some event handler that can be called at a later time. So I tend to like [&] for synchronous inline callbacks, and [x, y, z] for asynchronous event handlers.
Also feeling resistance when having to learn that
kj::heapreturns somethingstd::unique_ptr-like which implicit casts to raw pointer. Are thekjtypes only used when necessary to interface with Cap'n'Proto, andstdeverywhere else?
I think basically yes but the word "only" is too strong. The code does tends to use kj library when cap'nproto types are involved and std library otherwise. But there are probably exceptions, and I haven't found kj types and macros to cause problems in practice. In general kj types tend to have nice debugging and safety features and have a real rationale behind them. They are not just NIH. I think kj::Own in particular has capabilities std::unique_ptr doesn't have because it doesn't bake the deleter into the type definition, making it easier to support things like memory pools and implement zero-copy techniques cap'n proto uses internally.
There was a problem hiding this comment.
Your policy of only using [&] for indicating that the lambda will be called in current scope is nice when it comes to function-scope - as when creating server_connection, but less so in the case of TestSetup::server_disconnect when this is captured, which can perhaps be somewhat forgiven for a relatively simple lambda.
I agree that kj has some clever quirks that are missing from std. But is not a one-way street (implicit cast from Own to raw pointer for example). Would still advise towards using std when possible to make review more approachable. This passed mptest for example:
diff --git a/include/mp/proxy-io.h b/include/mp/proxy-io.h
index a0bdf13..6358c86 100644
--- a/include/mp/proxy-io.h
+++ b/include/mp/proxy-io.h
@@ -179,7 +179,7 @@ public:
//! Run function on event loop thread. Does not return until function completes.
//! Must be called while the loop() function is active.
- void post(kj::Function<void()> fn);
+ void post(std::function<void()> fn);
//! Wrapper around EventLoop::post that takes advantage of the
//! fact that callable will not go out of scope to avoid requirement that it
@@ -231,7 +231,7 @@ public:
std::thread m_async_thread;
//! Callback function to run on event loop thread during post() or sync() call.
- kj::Function<void()>* m_post_fn MP_GUARDED_BY(m_mutex) = nullptr;
+ std::function<void()>* m_post_fn MP_GUARDED_BY(m_mutex) = nullptr;
//! Callback functions to run on async thread.
std::optional<CleanupList> m_async_fns MP_GUARDED_BY(m_mutex);
diff --git a/src/mp/proxy.cpp b/src/mp/proxy.cpp
index 06825c9..6611cfb 100644
--- a/src/mp/proxy.cpp
+++ b/src/mp/proxy.cpp
@@ -263,7 +263,7 @@ void EventLoop::loop()
m_cv.notify_all();
}
-void EventLoop::post(kj::Function<void()> fn)
+void EventLoop::post(std::function<void()> fn)
{
if (std::this_thread::get_id() == m_thread_id) {
fn();There was a problem hiding this comment.
re: #201 (comment)
Nice find on lambda inconsistencies, that would make sense to clean up. Would be happy to review a PR with any cleanups and improvements like this.
On kj::Function vs std::function, this was actually changed recently in 52256e7 because std::function unlike kj::Function requires function objects to be copyable, which prevents writing lambdas that capture move-only objects. So I'm actually surprised that diff compiles. Maybe it compiles because it is only changing EventLoop::post not Waiter::post? Happy to change to whatever types work though.
ryanofsky
left a comment
There was a problem hiding this comment.
Thanks for the review and followups!
There was a problem hiding this comment.
re: https://github.com/bitcoin-core/libmultiprocess/pull/201/files#r2359060452
Tangent: Why does
EventLoopuse Unix sockets within the same process to signal when there's a newm_post_fnto execute? Seems like there should be thread synchronization primitives with marginally less overhead?
EventLoop documentation is meant to provide some background on this and specifically the link at the bottom https://groups.google.com/d/msg/capnproto/TuQFF1eH2-M/g81sHaTAAQAJ addresses this question.
Cap'n Proto doesn't use threads and assumes all code calling it runs on a single thread. There are benefits and costs that come from this but one of the costs is that external threads need to use I/O to communicate with cap'n proto's event loop. There isn't another way for threads to send signals. (Or at least there wasn't at time I wrote this, maybe newer versions of cap'n proto provide something)
There was a problem hiding this comment.
re: #201 (comment)
Tangent in unrelated file - regarding how easy it is to understand libmultiprocess:
TestSetup(in test/mp/test/test.cpp) is hard to read, maybe would benefit from adding comments with argument names of anonymous lambdas and explicit captures of variables.
This is probably true and I'm currently working on test improvements where I'm adding more members to the TestSetup class and could add more comments.
I'm not sure I would always prefer explicit variable captures though. I think [&] is not just a way of capturing state and cutting down noise, but also an important way indicating that the lambda will only be called in the current scope, and is not some event handler that can be called at a later time. So I tend to like [&] for synchronous inline callbacks, and [x, y, z] for asynchronous event handlers.
Also feeling resistance when having to learn that
kj::heapreturns somethingstd::unique_ptr-like which implicit casts to raw pointer. Are thekjtypes only used when necessary to interface with Cap'n'Proto, andstdeverywhere else?
I think basically yes but the word "only" is too strong. The code does tends to use kj library when cap'nproto types are involved and std library otherwise. But there are probably exceptions, and I haven't found kj types and macros to cause problems in practice. In general kj types tend to have nice debugging and safety features and have a real rationale behind them. They are not just NIH. I think kj::Own in particular has capabilities std::unique_ptr doesn't have because it doesn't bake the deleter into the type definition, making it easier to support things like memory pools and implement zero-copy techniques cap'n proto uses internally.
…st hang 535fa0a Squashed 'src/ipc/libmultiprocess/' changes from 13424cf2ecc1..47d79db8a552 (Ryan Ofsky) Pull request description: Includes: - bitcoin-core/libmultiprocess#207 - bitcoin-core/libmultiprocess#208 - bitcoin-core/libmultiprocess#211 - bitcoin-core/libmultiprocess#201 The last change fixes the test hang reported #33244 The changes can be verified by running `test/lint/git-subtree-check.sh src/ipc/libmultiprocess` as described in [developer notes](https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#subtrees) and [lint instructions](https://github.com/bitcoin/bitcoin/tree/master/test/lint#git-subtree-checksh) ACKs for top commit: Sjors: ACK c49a435 TheCharlatan: ACK c49a435 Tree-SHA512: e87e92caee20693d969308a9250804ffdea4d6fb84a23a2399c3ee43419e6dceb46a224e2410d35a5690dea14b5af9e94017a8f2ca733fa27781154ef8377e6d
47d79db8a5 Merge bitcoin-core/libmultiprocess#201: bug: fix mptest hang, ProxyClient<Thread> deadlock in disconnect handler f15ae9c9b9 Merge bitcoin-core/libmultiprocess#211: Add .gitignore 4a269b21b8 bug: fix ProxyClient<Thread> deadlock if disconnected as IPC call is returning 85df96482c Use try_emplace in SetThread instead of threads.find ca9b380ea9 Use std::optional in ConnThreads to allow shortening locks 9b07991135 doc: describe ThreadContext struct and synchronization requirements d60db601ed proxy-io.h: add Waiter::m_mutex thread safety annotations 4e365b019a ci: Use -Wthread-safety not -Wthread-safety-analysis 15d7bafbb0 Add .gitignore fe1cd8c761 Merge bitcoin-core/libmultiprocess#208: ci: Test minimum cmake version in olddeps job b713a0b7bf Merge bitcoin-core/libmultiprocess#207: ci: output CMake version in CI script 0f580397c9 ci: Test minimum cmake version in olddeps job d603dcc0ee ci: output CMake version in CI script 13424cf2ec Merge bitcoin-core/libmultiprocess#205: cmake: check for Cap'n Proto / Clang / C++20 incompatibility 72dce11864 Merge bitcoin-core/libmultiprocess#200: event loop: add LogOptions struct and reduce the log size 85003409f9 eventloop: add `LogOptions` struct 657d80622f cmake: capnproto pkg missing helpful error d314057775 cmake: check for Cap'n Proto / Clang / C++20 incompatibility 878e84dc30 Merge bitcoin-core/libmultiprocess#203: cmake: search capnproto in package mode only 1a85da5873 Merge bitcoin-core/libmultiprocess#202: doc: correct the build instructions for the example df01873e1e Merge bitcoin-core/libmultiprocess#197: ci: Add freebsd and macos build 3bee07ab33 cmake: search capnproto in package mode only b6d3dc4419 doc: correct the build instructions for example fa1ac30000 ci: Add macos and freebsd task git-subtree-dir: src/ipc/libmultiprocess git-subtree-split: 47d79db8a5528097b408e18f7b0bae11a6702d26
Use -Wthread-safety not -Wthread-safety-analysis in llvm and sanitize jobs. -Wthread-safety is a more general flag which adds additional checks outside the core thread safety analysis. Credit to hodlinator for noticing the bitcoin core build being stricter about thread safety checks than the libmultiprocess build here: bitcoin-core#201 (comment)
ryanofsky
left a comment
There was a problem hiding this comment.
Thanks for the followups, and I'd be happy to review a PR which cleans up code and makes it more readable or approachable!
There was a problem hiding this comment.
re: #201 (comment)
Yes IIRC wrapSocketFd does take ownership. A lot of this code is also updated & made more generic in windows PR bitcoin/bitcoin#32387 in case you are curious.
There was a problem hiding this comment.
re: #201 (comment)
Nice find on lambda inconsistencies, that would make sense to clean up. Would be happy to review a PR with any cleanups and improvements like this.
On kj::Function vs std::function, this was actually changed recently in 52256e7 because std::function unlike kj::Function requires function objects to be copyable, which prevents writing lambdas that capture move-only objects. So I'm actually surprised that diff compiles. Maybe it compiles because it is only changing EventLoop::post not Waiter::post? Happy to change to whatever types work though.
…+ polished docs ec03a96 doc: Precision and typos (Hodlinator) 2b43481 doc: Where possible, remove links to ryanofsky/bitcoin/ (Hodlinator) 286fe46 util: Add helpful error message when failing to execute file (Hodlinator) Pull request description: Found while reviewing #201. ACKs for top commit: ryanofsky: Code review ACK ec03a96 just addressing previous comments since last review: changing the missing executable check and updating markdown docs. All changes look very good now Eunovo: ACK ec03a96 theuni: utACK ec03a96 Tree-SHA512: a547c5bada848589729e73c0123c350f3fbc3fee880a8fdb4e3acffd75ead5383ec2adedd55c17ddc9073927fd5b0c89eceab0b75ffd7a5c87f0e2eca05fbfaf
…336e98 ec86e4336e98 Merge bitcoin-core/libmultiprocess#220: Add log levels and advertise them to users via logging callback 515ce93ad349 Logging: Pass LogData struct to logging callback 213574ccc43d Logging: reclassify remaining log messages e4de0412b430 Logging: Break out expensive log messages and classify them as Trace 408874a78fdc Logging: Use new logging macros 67b092d835cd Logging: Disable logging if messsage level is less than the requested level d0a1ba7ebf21 Logging: add log levels to mirror Core's 463a8296d188 Logging: Disable moving or copying Logger 83a2e10c0b03 Logging: Add an EventLoop constructor to allow for user-specified log options 58cf47a7fc8c Merge bitcoin-core/libmultiprocess#221: test default PassField impl handles output parameters db03a663f514 Merge bitcoin-core/libmultiprocess#214: Fix crash on simultaneous IPC calls using the same thread afcc40b0f1e8 Merge bitcoin-core/libmultiprocess#213: util+doc: Clearer errors when attempting to run examples + polished docs 6db669628387 test In|Out parameter 29cf2ada75ea test default PassField impl handles output parameters 1238170f68e8 test: simultaneous IPC calls using same thread eb069ab75d83 Fix crash on simultaneous IPC calls using the same thread ec03a9639ab5 doc: Precision and typos 2b4348193551 doc: Where possible, remove links to ryanofsky/bitcoin/ 286fe469c9c9 util: Add helpful error message when failing to execute file 47d79db8a552 Merge bitcoin-core/libmultiprocess#201: bug: fix mptest hang, ProxyClient<Thread> deadlock in disconnect handler f15ae9c9b9fb Merge bitcoin-core/libmultiprocess#211: Add .gitignore 4a269b21b8c8 bug: fix ProxyClient<Thread> deadlock if disconnected as IPC call is returning 85df96482c49 Use try_emplace in SetThread instead of threads.find ca9b380ea91a Use std::optional in ConnThreads to allow shortening locks 9b0799113557 doc: describe ThreadContext struct and synchronization requirements d60db601ed9b proxy-io.h: add Waiter::m_mutex thread safety annotations 4e365b019a9f ci: Use -Wthread-safety not -Wthread-safety-analysis 15d7bafbb001 Add .gitignore fe1cd8c76131 Merge bitcoin-core/libmultiprocess#208: ci: Test minimum cmake version in olddeps job b713a0b7bfbc Merge bitcoin-core/libmultiprocess#207: ci: output CMake version in CI script 0f580397c913 ci: Test minimum cmake version in olddeps job d603dcc0eef0 ci: output CMake version in CI script git-subtree-dir: src/ipc/libmultiprocess git-subtree-split: ec86e4336e986a02b08ab12f7eea9f74551c5bef
…696490 a4f929696490 Merge bitcoin-core/libmultiprocess#224: doc: fix typos f4344ae87da0 Merge bitcoin-core/libmultiprocess#222: test, ci: Fix threadsanitizer errors in mptest 1434642b3804 doc: fix typos 73d22ba2e930 test: Fix tsan race in thread busy test b74e1bba014d ci: Use tsan-instrumented cap'n proto in sanitizers job c332774409ad test: Fix failing exception check in new thread busy test ca3c05d56709 test: Use KJ_LOG instead of std::cout for logging 7eb1da120ab6 ci: Use tsan-instrumented libcxx in sanitizers job ec86e4336e98 Merge bitcoin-core/libmultiprocess#220: Add log levels and advertise them to users via logging callback 515ce93ad349 Logging: Pass LogData struct to logging callback 213574ccc43d Logging: reclassify remaining log messages e4de0412b430 Logging: Break out expensive log messages and classify them as Trace 408874a78fdc Logging: Use new logging macros 67b092d835cd Logging: Disable logging if messsage level is less than the requested level d0a1ba7ebf21 Logging: add log levels to mirror Core's 463a8296d188 Logging: Disable moving or copying Logger 83a2e10c0b03 Logging: Add an EventLoop constructor to allow for user-specified log options 58cf47a7fc8c Merge bitcoin-core/libmultiprocess#221: test default PassField impl handles output parameters db03a663f514 Merge bitcoin-core/libmultiprocess#214: Fix crash on simultaneous IPC calls using the same thread afcc40b0f1e8 Merge bitcoin-core/libmultiprocess#213: util+doc: Clearer errors when attempting to run examples + polished docs 6db669628387 test In|Out parameter 29cf2ada75ea test default PassField impl handles output parameters 1238170f68e8 test: simultaneous IPC calls using same thread eb069ab75d83 Fix crash on simultaneous IPC calls using the same thread ec03a9639ab5 doc: Precision and typos 2b4348193551 doc: Where possible, remove links to ryanofsky/bitcoin/ 286fe469c9c9 util: Add helpful error message when failing to execute file 47d79db8a552 Merge bitcoin-core/libmultiprocess#201: bug: fix mptest hang, ProxyClient<Thread> deadlock in disconnect handler f15ae9c9b9fb Merge bitcoin-core/libmultiprocess#211: Add .gitignore 4a269b21b8c8 bug: fix ProxyClient<Thread> deadlock if disconnected as IPC call is returning 85df96482c49 Use try_emplace in SetThread instead of threads.find ca9b380ea91a Use std::optional in ConnThreads to allow shortening locks 9b0799113557 doc: describe ThreadContext struct and synchronization requirements d60db601ed9b proxy-io.h: add Waiter::m_mutex thread safety annotations 4e365b019a9f ci: Use -Wthread-safety not -Wthread-safety-analysis 15d7bafbb001 Add .gitignore fe1cd8c76131 Merge bitcoin-core/libmultiprocess#208: ci: Test minimum cmake version in olddeps job b713a0b7bfbc Merge bitcoin-core/libmultiprocess#207: ci: output CMake version in CI script 0f580397c913 ci: Test minimum cmake version in olddeps job d603dcc0eef0 ci: output CMake version in CI script git-subtree-dir: src/ipc/libmultiprocess git-subtree-split: a4f92969649018ca70f949a09148bccfeaecd99a
abcd4c4 Squashed 'src/ipc/libmultiprocess/' changes from 13424cf2ecc1..a4f929696490 (Ryan Ofsky) Pull request description: Includes: - bitcoin-core/libmultiprocess#207 - bitcoin-core/libmultiprocess#208 - bitcoin-core/libmultiprocess#211 - bitcoin-core/libmultiprocess#201 - bitcoin-core/libmultiprocess#213 - bitcoin-core/libmultiprocess#214 - bitcoin-core/libmultiprocess#221 - bitcoin-core/libmultiprocess#220 - bitcoin-core/libmultiprocess#222 - bitcoin-core/libmultiprocess#224 Corresponding to #32641 and #33518 in master. The changes can be verified by running `test/lint/git-subtree-check.sh src/ipc/libmultiprocess` as described in [developer notes](https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#subtrees) and [lint instructions](https://github.com/bitcoin/bitcoin/tree/master/test/lint#git-subtree-checksh) They can also be verified by checking `src/ipc/libmultiprocess/` contents are the same in master. (See also #33439). ACKs for top commit: Sjors: ACK ae63cc4 theuni: ACK ae63cc4 . Verified that it's the same as what's in master. Tree-SHA512: 6c9462d5fb9201ee8ace900d7d02bfb6d0c7aa3d2f22475dc55e55e0239e2d20ed69f572c0df233da7910375e9d8ccaf3e84bf949ae92df27b88f16adb26dd7a
abcd4c4 Squashed 'src/ipc/libmultiprocess/' changes from 13424cf2ecc1..a4f929696490 (Ryan Ofsky) Pull request description: Includes: - bitcoin-core/libmultiprocess#207 - bitcoin-core/libmultiprocess#208 - bitcoin-core/libmultiprocess#211 - bitcoin-core/libmultiprocess#201 - bitcoin-core/libmultiprocess#213 - bitcoin-core/libmultiprocess#214 - bitcoin-core/libmultiprocess#221 - bitcoin-core/libmultiprocess#220 - bitcoin-core/libmultiprocess#222 - bitcoin-core/libmultiprocess#224 Corresponding to bitcoin#32641 and bitcoin#33518 in master. The changes can be verified by running `test/lint/git-subtree-check.sh src/ipc/libmultiprocess` as described in [developer notes](https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md#subtrees) and [lint instructions](https://github.com/bitcoin/bitcoin/tree/master/test/lint#git-subtree-checksh) They can also be verified by checking `src/ipc/libmultiprocess/` contents are the same in master. (See also bitcoin#33439). ACKs for top commit: Sjors: ACK 7788449 theuni: ACK 7788449 . Verified that it's the same as what's in master. Tree-SHA512: 6c9462d5fb9201ee8ace900d7d02bfb6d0c7aa3d2f22475dc55e55e0239e2d20ed69f572c0df233da7910375e9d8ccaf3e84bf949ae92df27b88f16adb26dd7a
27ada40809 build: move library sources under lib/ for subtree split REVERT: 3c69d125a1 Merge bitcoin-core/libmultiprocess#260: event loop: tolerate unexpected exceptions in `post()` callbacks REVERT: b8a48c65e6 event loop: tolerate unexpected exceptions in `post()` callbacks REVERT: f787863d2c Merge bitcoin-core/libmultiprocess#270: doc: Bump version 10 > 11 REVERT: a22f602910 doc: Bump version 10 > 11 REVERT: 3edbe8f67c Merge bitcoin-core/libmultiprocess#268: Use throwRecoverableException instead of raw throw for stored exceptions REVERT: 23be44b0d3 Use throwRecoverableException instead of raw throw for stored exceptions REVERT: 75c2a2764c Merge bitcoin-core/libmultiprocess#266: test: increase spawn test child timeout to 30 seconds REVERT: 8b5f805301 Merge bitcoin-core/libmultiprocess#267: doc: Bump version 9 > 10 REVERT: cc0b23fc32 test: increase spawn test child timeout to 30 seconds REVERT: 050f878db8 doc: Improve versions.md descriptions and formatting REVERT: c6a288a889 doc: Bump version 9 > 10 REVERT: 70f632bda8 Merge bitcoin-core/libmultiprocess#265: ci: set LC_ALL in shell scripts REVERT: 8e8e564259 Merge bitcoin-core/libmultiprocess#249: fixes for race conditions on disconnects REVERT: 05d34cc2ec ci: set LC_ALL in shell scripts REVERT: e606fd84a8 Merge bitcoin-core/libmultiprocess#264: ci: reduce nproc multipliers REVERT: ff0eed1bf1 refactor: Use loop variable in type-context.h REVERT: ff1d8ba172 refactor: Move type-context.h getParams() call closer to use REVERT: 1dbc59a4aa race fix: m_on_cancel called after request finishes REVERT: 1643d05ba0 test: m_on_cancel called after request finishes REVERT: f5509a31fc race fix: getParams() called after request cancel REVERT: 4a60c39f24 test: getParams() called after request cancel REVERT: f11ec29ed2 race fix: worker thread destroyed before it is initialized REVERT: a1d643348f test: worker thread destroyed before it is initialized REVERT: 336023382c ci: reduce nproc multipliers REVERT: b090beb965 Merge bitcoin-core/libmultiprocess#256: ci: cache gnu32 nix store REVERT: be8622816d ci: cache gnu32 nix store REVERT: 975270b619 Merge bitcoin-core/libmultiprocess#263: ci: bump timeout factor to 40 REVERT: 09f10e5a59 ci: bump timeout factor to 40 REVERT: db8f76ad29 Merge bitcoin-core/libmultiprocess#253: ci: run some Bitcoin Core CI jobs REVERT: 55a9b557b1 ci: set Bitcoin Core CI test repetition REVERT: fb0fc84d55 ci: add TSan job with instrumented libc++ REVERT: 0f29c38725 ci: add Bitcoin Core IPC tests (ASan + macOS) REVERT: 3f64320315 Merge bitcoin-core/libmultiprocess#262: ci: enable clang-tidy in macOS job, use nullptr REVERT: cd9f8bdc9f Merge bitcoin-core/libmultiprocess#258: log: add socket connected info message and demote destroy logs to debug REVERT: b5d6258a42 Merge bitcoin-core/libmultiprocess#255: fix: use unsigned char cast and sizeof in LogEscape escape sequence REVERT: d94688e2c3 Merge bitcoin-core/libmultiprocess#251: Improved CustomBuildField for std::optional in IPC/libmultiprocess REVERT: a9499fad75 mp: use nullptr with pthread_threadid_np REVERT: f499e37850 ci: enable clang-tidy in macOS job REVERT: 98f1352159 log: add socket connected info message and demote destroy logs to debug REVERT: 554a481ea7 fix: use unsigned char cast and sizeof in LogEscape escape sequence REVERT: 1977b9f3f6 Use std::forward in CustomBuildField for std::optional to allow move semantics, resolves FIXME REVERT: 22bec918c9 Merge bitcoin-core/libmultiprocess#247: type-map: Work around LLVM 22 "out of bounds index" error REVERT: 8a5e3ae6ed Merge bitcoin-core/libmultiprocess#242: proxy-types: add CustomHasField hook to map Cap'n Proto values to null C++ values REVERT: e8d3524691 Merge bitcoin-core/libmultiprocess#246: doc: Bump version 8 > 9 REVERT: 97d877053b proxy-types: add CustomHasField hook for nullable decode paths REVERT: 8c2f10252c refactor: add missing includes to mp/type-data.h REVERT: b1638aceb4 doc: Bump version 8 > 9 REVERT: f61af48721 type-map: Work around LLVM 22 "out of bounds index" error REVERT: 1868a84451 Merge bitcoin-core/libmultiprocess#245: type-context.h: Extent cancel_mutex lock to prevent theoretical race REVERT: fd4a90d310 Merge bitcoin-core/libmultiprocess#244: ci: suppress two tidy lint issues REVERT: 16dfc36864 ci: avoid bugprone-unused-return-value lint in test REVERT: dacd5eda46 ci: suppress nontrivial-threadlocal lint in proxy.cpp REVERT: ef96a5b2be doc: Comment cleanups after bitcoin#240 REVERT: e0f1cd7621 type-context.h: Extent cancel_mutex lock to prevent theoretical race REVERT: 290702c74c Merge bitcoin-core/libmultiprocess#240: Avoid errors from asynchronous (non-c++) clients REVERT: 3a69d4755a Merge bitcoin-core/libmultiprocess#241: doc: Bump version number v7 -> v8 REVERT: 0174450ca2 Prevent crash on unclean disconnect if abandoned IPC call returns interface pointer REVERT: ddb5f74196 Allow simultaneous calls on same Context.thread REVERT: c4762c7b51 refactor: Add ProxyServer<Thread>::post() method REVERT: 0ade1b40ac doc: Bump version number REVERT: 1fc65008f7 Merge bitcoin-core/libmultiprocess#237: Made SpawnProcess() behavior safe post fork() REVERT: 5205a87cd9 test: check SpawnProcess post-fork safety REVERT: 69652f0edf Precompute argv before fork in SpawnProcess REVERT: 30a8681de6 SpawnProcess: avoid fd leak on close failure REVERT: d0fc1081d0 Merge bitcoin-core/libmultiprocess#196: ci: Add NetBSD job REVERT: 7b171f45bf Merge bitcoin-core/libmultiprocess#234: doc: Fix typos and grammar in documentation and comments REVERT: 861da39cae ci: Add NetBSD job REVERT: 458745e394 Fix various typos, spelling mistakes, and grammatical errors in design.md and source code comments. REVERT: 585decc856 Merge bitcoin-core/libmultiprocess#236: ci: Install binary package `capnproto` on OpenBSD instead of building it REVERT: 14e926a3ff refactor: extract MakeArgv helper REVERT: 1ee909393f ci: Install binary package `capnproto` on OpenBSD instead of building it REVERT: 470fc518d4 Merge bitcoin-core/libmultiprocess#230: cmake: add ONLY_CAPNP target_capnp_sources option REVERT: 2d8886f26c Merge bitcoin-core/libmultiprocess#228: Add versions.md and version.h files describing version branches and tags REVERT: c1838be565 Merge bitcoin-core/libmultiprocess#225: Improve and document act support REVERT: a173f1704c Merge bitcoin-core/libmultiprocess#223: ci: Replace nix-shell with equivalent nix develop command REVERT: 625eaca42f Merge bitcoin-core/libmultiprocess#229: Design Documentation Update REVERT: cc234be73a Design doc update REVERT: 81c652687b cmake: add ONLY_CAPNP target_capnp_sources option REVERT: 6e01d2d766 Add versions.md and version.h files describing version branches and tags REVERT: a4f9296964 Merge bitcoin-core/libmultiprocess#224: doc: fix typos REVERT: f4344ae87d Merge bitcoin-core/libmultiprocess#222: test, ci: Fix threadsanitizer errors in mptest REVERT: 4e3f8fa0d2 doc: add instructions for using act REVERT: 81712ff6bb ci: disable KVM and sandbox inside act containers REVERT: 1434642b38 doc: fix typos REVERT: 73d22ba2e9 test: Fix tsan race in thread busy test REVERT: b74e1bba01 ci: Use tsan-instrumented cap'n proto in sanitizers job REVERT: c332774409 test: Fix failing exception check in new thread busy test REVERT: ca3c05d567 test: Use KJ_LOG instead of std::cout for logging REVERT: 7eb1da120a ci: Use tsan-instrumented libcxx in sanitizers job REVERT: 18a2237a8e ci: Replace nix-shell with equivalent nix develop command REVERT: ec86e4336e Merge bitcoin-core/libmultiprocess#220: Add log levels and advertise them to users via logging callback REVERT: 515ce93ad3 Logging: Pass LogData struct to logging callback REVERT: 213574ccc4 Logging: reclassify remaining log messages REVERT: e4de0412b4 Logging: Break out expensive log messages and classify them as Trace REVERT: 408874a78f Logging: Use new logging macros REVERT: 67b092d835 Logging: Disable logging if messsage level is less than the requested level REVERT: d0a1ba7ebf Logging: add log levels to mirror Core's REVERT: 463a8296d1 Logging: Disable moving or copying Logger REVERT: 83a2e10c0b Logging: Add an EventLoop constructor to allow for user-specified log options REVERT: 58cf47a7fc Merge bitcoin-core/libmultiprocess#221: test default PassField impl handles output parameters REVERT: db03a663f5 Merge bitcoin-core/libmultiprocess#214: Fix crash on simultaneous IPC calls using the same thread REVERT: afcc40b0f1 Merge bitcoin-core/libmultiprocess#213: util+doc: Clearer errors when attempting to run examples + polished docs REVERT: 6db6696283 test In|Out parameter REVERT: 29cf2ada75 test default PassField impl handles output parameters REVERT: 1238170f68 test: simultaneous IPC calls using same thread REVERT: eb069ab75d Fix crash on simultaneous IPC calls using the same thread REVERT: ec03a9639a doc: Precision and typos REVERT: 2b43481935 doc: Where possible, remove links to ryanofsky/bitcoin/ REVERT: 286fe469c9 util: Add helpful error message when failing to execute file REVERT: 47d79db8a5 Merge bitcoin-core/libmultiprocess#201: bug: fix mptest hang, ProxyClient<Thread> deadlock in disconnect handler REVERT: f15ae9c9b9 Merge bitcoin-core/libmultiprocess#211: Add .gitignore REVERT: 4a269b21b8 bug: fix ProxyClient<Thread> deadlock if disconnected as IPC call is returning REVERT: 85df96482c Use try_emplace in SetThread instead of threads.find REVERT: ca9b380ea9 Use std::optional in ConnThreads to allow shortening locks REVERT: 9b07991135 doc: describe ThreadContext struct and synchronization requirements REVERT: d60db601ed proxy-io.h: add Waiter::m_mutex thread safety annotations REVERT: 4e365b019a ci: Use -Wthread-safety not -Wthread-safety-analysis REVERT: 15d7bafbb0 Add .gitignore REVERT: fe1cd8c761 Merge bitcoin-core/libmultiprocess#208: ci: Test minimum cmake version in olddeps job REVERT: b713a0b7bf Merge bitcoin-core/libmultiprocess#207: ci: output CMake version in CI script REVERT: 0f580397c9 ci: Test minimum cmake version in olddeps job REVERT: d603dcc0ee ci: output CMake version in CI script REVERT: 13424cf2ec Merge bitcoin-core/libmultiprocess#205: cmake: check for Cap'n Proto / Clang / C++20 incompatibility REVERT: 72dce11864 Merge bitcoin-core/libmultiprocess#200: event loop: add LogOptions struct and reduce the log size REVERT: 85003409f9 eventloop: add `LogOptions` struct REVERT: 657d80622f cmake: capnproto pkg missing helpful error REVERT: d314057775 cmake: check for Cap'n Proto / Clang / C++20 incompatibility REVERT: 878e84dc30 Merge bitcoin-core/libmultiprocess#203: cmake: search capnproto in package mode only REVERT: 1a85da5873 Merge bitcoin-core/libmultiprocess#202: doc: correct the build instructions for the example REVERT: df01873e1e Merge bitcoin-core/libmultiprocess#197: ci: Add freebsd and macos build REVERT: 3bee07ab33 cmake: search capnproto in package mode only REVERT: b6d3dc4419 doc: correct the build instructions for example REVERT: fa1ac30000 ci: Add macos and freebsd task REVERT: 1b8d4a6f1e Merge bitcoin-core/libmultiprocess#194: mpgen: Work around c++20 / capnproto 0.8 incompatibility REVERT: f1fad396bf Merge bitcoin-core/libmultiprocess#195: ci: Add openbsd REVERT: eed42f210d ci: Bump all tasks to actions/checkout@v5 REVERT: 486a510bbe ci: Remove ancient and problematic -lstdc++fs in mpexample REVERT: dd40897efe Add missing thread include REVERT: 98414e7d28 ci: Add openbsd REVERT: dc3ba22046 cmake, doc: Add check for CVE-2022-46149 REVERT: cb170d4913 Merge bitcoin-core/libmultiprocess#193: build: require CapnProto 0.7.0 or better REVERT: 8ceeaa6ae4 ci: Add olddeps job to test old dependencies versions REVERT: c4cb758ecc mpgen: Work around c++20 / capnproto 0.8 incompatibility REVERT: 30930dff7b build: require CapnProto 0.7.0 or better REVERT: b4120d34ba Merge bitcoin-core/libmultiprocess#192: doc: fix typos REVERT: 6ecbdcd35a doc: fix typos REVERT: a11e6905c2 Merge bitcoin-core/libmultiprocess#186: Fix mptest failures in bitcoin CI REVERT: 6f340a583f doc: fix DrahtBot LLM Linter error REVERT: c6f7fdf173 type-context: revert client disconnect workaround REVERT: e09143d2ea proxy-types: fix UndefinedBehaviorSanitizer: null-pointer-use REVERT: 84b292fcc4 mptest: fix MemorySanitizer: use-of-uninitialized-value REVERT: fe4a188803 proxy-io: fix race conditions in disconnect callback code REVERT: d8011c8360 proxy-io: fix race conditions in ProxyClientBase cleanup handler REVERT: 97e82ce19c doc: Add note about Waiter::m_mutex and interaction with the EventLoop::m_mutex REVERT: 81d58f5580 refactor: Rename ProxyClient cleanup_it variable REVERT: 07230f259f refactor: rename ProxyClient<Thread>::m_cleanup_it REVERT: c0efaa5e8c Merge bitcoin-core/libmultiprocess#187: ci: have bash scripts explicitly opt out of locale dependence. REVERT: 0d986ff144 mptest: fix race condition in TestSetup constructor REVERT: d2f6aa2e84 ci: add thread sanitizer job REVERT: 3a6db38e56 ci: rename configs to .bash REVERT: 401e0ce1d9 ci: add copyright to bash scripts REVERT: e956467ae4 ci: export LC_ALL REVERT: 8954cc0377 Merge bitcoin-core/libmultiprocess#184: Add CI jobs and fix clang-tidy and iwyu errors REVERT: 757e13a755 ci: add gnu32 cross-compiled 32-bit build REVERT: 15bf349000 doc: fix typo found by DrahtBot REVERT: 1a598d5905 clang-tidy: drop 'bitcoin-*' check REVERT: cbb1e43fdc ci: test libc++ instead of libstdc++ in one job REVERT: 76313450c2 type-context: disable clang-tidy UndefinedBinaryOperatorResult error REVERT: 4896e7fe51 proxy-types: fix clang-tidy EnumCastOutOfRange error REVERT: 060a739269 proxy-types: fix clang-tidy StackAddressEscape error REVERT: 977d721020 ci: add github actions jobs testing gcc, clang-20, clang-tidy, and iwyu REVERT: 0d5f1faae5 iwyu: fix add/remove include errors REVERT: 753d2b10cc util: fix clang-tidy modernize-use-equals-default error REVERT: ae4f1dc2bb type-number: fix clang-tidy modernize-use-nullptr error REVERT: 07a741bf69 proxy-types: fix clang-tidy bugprone-use-after-move error REVERT: 3673114bc9 proxy-types: fix clang-tidy bugprone-use-after-move error REVERT: 422923f384 proxy-types: fix clang-tidy bugprone-use-after-move error REVERT: c6784c6ade mpgen: disable clang-tidy misc-no-recursion error REVERT: c5498aa11b tidy: copy clang-tidy file from bitcoin core REVERT: 258a617c1e Merge bitcoin-core/libmultiprocess#160: refactor: EventLoop locking cleanups + client disconnect exception REVERT: 84cf56a0b5 test: Test disconnects during IPC calls REVERT: 949573da84 Prevent IPC server crash if disconnected during IPC call REVERT: 0198397580 Merge bitcoin-core/libmultiprocess#179: scripted-diff: Remove copyright year (ranges) REVERT: ea38392960 Prevent EventLoop async cleanup thread early exit during shutdown REVERT: 616d9a75d2 doc: Document ProxyClientBase destroy_connection option REVERT: 56fff76f94 Improve IPC client disconnected exceptions REVERT: 9b8ed3dc5f refactor: Add clang thread safety annotations to EventLoop REVERT: 52256e730f refactor: Remove DestructorCatcher and AsyncCallable REVERT: f24894794a refactor: Drop addClient/removeClient methods REVERT: 2b830e558e refactor: Use EventLoopRef instead of addClient/removeClient REVERT: 315ff537fb refactor: Add ProxyContext EventLoop* member REVERT: 9aaeec3678 proxy-io.h: Add EventLoopRef RAII class handle addClient/removeClient refcounting REVERT: f58c8d8ba2 proxy-io.h: Add more detailed EventLoop comment REVERT: 5108445e5d test: Add test coverage for client & server disconnections REVERT: 59030c68cb Merge bitcoin-core/libmultiprocess#181: type-function.h: Fix CustomBuildField overload REVERT: 688140b1df test: Add coverage for type-function.h REVERT: 8b96229da5 type-function.h: Fix CustomBuildField overload REVERT: fa2ff9a668 scripted-diff: Remove copyright year (ranges) REVERT: 27c7e8e5a5 Merge bitcoin-core/libmultiprocess#172: refactor: fix warnings from clang-tidy-20 and bitcoin-tidy REVERT: 2fe87d016b Merge bitcoin-core/libmultiprocess#173: doc: Fix error string typo REVERT: 57a65b8546 clang-tidy: Suppress bitcoin-nontrivial-threadlocal error REVERT: 0d8012f656 Merge bitcoin-core/libmultiprocess#165: clang-tidy: fix warnings introduced in version 19 REVERT: 3a96cdc18f clang-tidy: Fix bugprone-move-forwarding-reference error REVERT: c1e8c1a028 clang-tidy: Fix bugprone-move-forwarding-reference errors REVERT: aa19285303 use ranges transform REVERT: a78137ca73 make member function const REVERT: ca3226ec8a replace custom tuple unpacking code with `std::apply` REVERT: 949fe85fc9 replace SFINAE trick with `if constexpr` REVERT: 44ee4b40b8 doc: Fix error string typo REVERT: 35944ffd23 Merge bitcoin-core/libmultiprocess#168: Switch `MP_INCLUDE_DIR` to global property REVERT: a77c8e18eb Switch `MP_INCLUDE_DIR` to global property REVERT: f35df6bdc5 Merge bitcoin-core/libmultiprocess#166: doc: rename from chaincodelabs to bitcoin-core REVERT: 2e119973ce doc: rename from chaincodelabs to bitcoin-core REVERT: 1954f7f656 Merge bitcoin-core/libmultiprocess#164: Bump minimum required cmake to 3.12 REVERT: 729ff16d55 Bump minimum required cmake to 3.12 REVERT: 011fc53aea Merge bitcoin-core/libmultiprocess#161: cmake: Avoid including CTest if not top level project REVERT: 26b9f3dda4 Merge bitcoin-core/libmultiprocess#159: bugfix: Do not lock EventLoop::mutex after EventLoop is done REVERT: a7f0669320 cmake: Avoid including CTest if not top level project REVERT: 48d01bcca7 bugfix: Do not lock EventLoop::mutex after EventLoop is done REVERT: 408990787f Merge bitcoin-core/libmultiprocess#157: refactor: Avoid using std::format REVERT: eca8fd3eee refactor: Avoid using std::format REVERT: 9ba88dc2c7 Merge bitcoin-core/libmultiprocess#156: refactor: Remove locale-dependent function calls REVERT: 91193005a9 Merge bitcoin-core/libmultiprocess#155: scripted-diff: s/Libmultiprocess_EXTERNAL_MPGEN/MPGEN_EXECUTABLE/g REVERT: c8351c5f0b refactor: Remove locale-dependent function calls REVERT: 250c2ea54d scripted-diff: s/Libmultiprocess_EXTERNAL_MPGEN/MPGEN_EXECUTABLE/g REVERT: 9558ceb0d4 Merge bitcoin-core/libmultiprocess#152: refactor: Fix compiler and clang-tidy warnings REVERT: c6a61d8b9e Merge bitcoin-core/libmultiprocess#149: Avoid `-Wundef` compiler warnings REVERT: 0b8b7f92ca refactor: Fix `-Wsign-compare` compiler warning REVERT: a02c0794fd clang-tidy: Suppress `performance-enum-size` check warning REVERT: 593807ab5b clang-tidy: Fix `readability-container-size-empty` check REVERT: 68c1c6c51a clang-tidy: Fix `readability-avoid-return-with-void-value` check REVERT: 4abaa98429 clang-tidy: Fix `readability-avoid-nested-conditional-operator` check REVERT: 01ef094b4c clang-tidy: Fix `performance-unnecessary-value-param` check REVERT: c665a43f9c clang-tidy: Fix `misc-use-internal-linkage` check REVERT: 15c77e9722 clang-tidy: Fix `misc-include-cleaner` check REVERT: 848c902dd0 clang-tidy: Fix `misc-const-correctness` check REVERT: 4a2508c499 clang-tidy: Fix `modernize-type-traits` check REVERT: 8170d3d421 clang-tidy: Suppress `bugprone-empty-catch` check warning REVERT: c068596ac3 clang-tidy: Fix `bugprone-crtp-constructor-accessibility` check REVERT: 00036c0648 clang-tidy: Disable `performance-avoid-endl` check REVERT: 359a6157af clang-tidy: Disable `misc-use-anonymous-namespace` check REVERT: c978878a3c Merge bitcoin-core/libmultiprocess#145: CTest: Module must be included at the top level REVERT: 63ac092ddd CTest: Module must be included at the top level REVERT: d450fbf63e Avoid `-Wundef` compiler warnings REVERT: 477405eda3 Merge bitcoin-core/libmultiprocess#148: util: fix -Wpessimizing-move warning REVERT: 3bce9d03d1 util: fix -Wpessimizing-move warning REVERT: f09c50118f Merge bitcoin-core/libmultiprocess#147: cmake: EXTERNAL_MPGEN cleanups REVERT: 3d83c7aef1 Merge bitcoin-core/libmultiprocess#146: cmake: Suppress compiler warnings from capnproto headers REVERT: 21b92b69c9 cmake: EXTERNAL_MPGEN cleanups REVERT: 2fdd920b1e Merge bitcoin-core/libmultiprocess#143: cleanup: initialize vars in the EventLoop constructor in the correct order REVERT: 0c2ac4d772 Merge bitcoin-core/libmultiprocess#142: build: add option for external mpgen binary REVERT: f52d08c7f0 cleanup: initialize vars in the EventLoop constructor in the correct order REVERT: 75cf04a6ed build: add option for external mpgen binary REVERT: 72326b5d1e cmake: Simplify capnp include handling REVERT: 1e06ff07cd Merge bitcoin-core/libmultiprocess#140: build: don't clobber user/superproject c++ version REVERT: 65c7048251 cmake: Suppress compiler warnings from capnproto headers REVERT: df2153551e build: don't clobber user/superproject c++ version REVERT: 07c917f7ca Merge bitcoin-core/libmultiprocess#137: doc: Fix broken markdown links REVERT: e15816a6c3 doc: Fix broken markdown links REVERT: e89b2c6ac2 Merge bitcoin-core/libmultiprocess#136: cmake: Support being included with add_subdirectory REVERT: 3dea1d555a Merge bitcoin-core/libmultiprocess#135: refactor: proxy-types.h API cleanup REVERT: 6adbb1d6eb cmake: Support being included with add_subdirectory REVERT: 10bb7e4734 Merge bitcoin-core/libmultiprocess#94: c++ 20 cleanups REVERT: 7d59b8d14c move: add mp/type-data.h REVERT: 1103f86cd9 cmake: Define and use MP_INCLUDE_DIR variable REVERT: 798f4b5e35 moveonly: add mp/type-chrono.h REVERT: a595a0b228 moveonly: add mp/type-threadmap.h REVERT: e834ebd219 moveonly: add mp/type-decay.h REVERT: 5ee6cd4118 moveonly: add mp/type-exception.h REVERT: 394651237b moveonly: add mp/type-void.h REVERT: 8969d5a008 moveonly: add mp/type-message.h REVERT: 11b418f438 moveonly: add mp/type-struct.h REVERT: 5df55a3666 moveonly: add mp/type-function.h REVERT: 0d2f939214 moveonly: add mp/type-interface.h REVERT: 5417716ad8 moveonly: add mp/type-char.h REVERT: 83c444dc9d moveonly: add mp/type-string.h REVERT: df1375bd68 moveonly: add mp/type-number.h REVERT: 6d831ebb1d moveonly: add mp/type-tuple.h REVERT: c999100289 moveonly: add mp/type-pair.h REVERT: 079277f2ba moveonly: add mp/type-map.h REVERT: 6a68472bb3 moveonly: add mp/type-set.h REVERT: c6246c9198 moveonly: add mp/type-vector.h REVERT: 619d2c7405 moveonly: add mp/type-pointer.h REVERT: 3cb9d9fd5b moveonly: add mp/type-optional.h REVERT: b32e2b096c moveonly: add mp/type-context.h REVERT: f18a1ccd20 refactor: Rename ReadDestValue to ReadDestUpdate REVERT: 3dc1d42a7a Merge bitcoin-core/libmultiprocess#133: Fix debian "libatomic not found" error in downstream builds REVERT: eb27f5918f Merge bitcoin-core/libmultiprocess#131: doc: fix startAsyncThread comment REVERT: caf01fa469 Merge bitcoin-core/libmultiprocess#130: refactor: Add CleanupRun function to dedup clean list code REVERT: 72f6669b50 Merge bitcoin-core/libmultiprocess#129: Fix "disconnected: write(m_post_fd, &buffer, 1): Broken pipe" EventLoop shutdown races. REVERT: 67afc23069 Fix debian "libatomic not found" error in downstream builds REVERT: 0e4f88d3f9 Fix "disconnected: write(m_post_fd, &buffer, 1): Broken pipe" EventLoop shutdown races. REVERT: 063ff18210 fix startAsyncThread comment REVERT: 3b2617b3e5 Merge bitcoin-core/libmultiprocess#127: ProxyClientBase: avoid static_cast to partially destructed object REVERT: 63a39d4c9b ProxyClientBase: avoid static_cast to partially destructed object REVERT: 700085f9a8 refactor: Add CleanupRun function to dedup clean list code REVERT: 621a04a70f Merge bitcoin-core/libmultiprocess#120: proxy-types.h: add static_assert to detect int/enum size mismatch REVERT: 110349f626 test: Add coverage for enum/int conversions REVERT: 350067f431 Merge bitcoin-core/libmultiprocess#121: ProxyClientBase: avoid static_cast to partially constructed object REVERT: 5b81192847 ProxyClientBase: avoid static_cast to partially constructed object REVERT: bbc80abc20 proxy-types.h: add static_assert to detect when an int fields is too small to hold an enum value REVERT: abe254b973 Merge bitcoin-core/libmultiprocess#119: cmake: avoid libatomic not found error on debian REVERT: 245581d3e3 Merge bitcoin-core/libmultiprocess#118: shutdown bugfix: Prevent segfault in server if connection is broken during long function call REVERT: 196e6fcdbc bugfix: prevent null pointer dereference in server if client disconnects during method call REVERT: 296c380a4b cmake: avoid libatomic not found error on debian REVERT: 9d11042772 bugfix: prevent double delete segfault in server if client disconnects during method call REVERT: 181837b391 Merge bitcoin-core/libmultiprocess#116: shutdown bugfix: destroy RPC system before running cleanup callbacks REVERT: 2350843a31 shutdown bugfix: destroy RPC system before running cleanup callbacks REVERT: a4ac4241e0 Merge bitcoin-core/libmultiprocess#113: Add missing include to util.h REVERT: 6929c40913 Add missing include to util.h REVERT: f5a4957d26 Merge bitcoin-core/libmultiprocess#111: doc: Add internal design section REVERT: 1fa2ca7cd8 doc: Add internal design section REVERT: 015e95f7eb Merge bitcoin-core/libmultiprocess#110: cmake: add target_capnp_sources headers target REVERT: 66e12f1fae cmake: add target_capnp_sources headers target REVERT: f67cae8909 Merge bitcoin-core/libmultiprocess#109: example: Add missing thread.join() call so example can exit cleanly REVERT: 70b2d8794f example: Add missing thread.join() call so example can exit cleanly REVERT: 8bb6eab71b Merge bitcoin-core/libmultiprocess#108: doc: Add comments for socket descriptor handling when forking REVERT: 17a2399fe1 Merge bitcoin-core/libmultiprocess#107: example: Remove manual client adding REVERT: b56bf218c7 doc: Add comments for socket descriptor handling when forking REVERT: 34998101a3 example: Remove manual client adding REVERT: c1b4ab4eb8 Merge bitcoin-core/libmultiprocess#106: Bugfix: Clean up ThreadContext pointers when Connection is destroyed REVERT: 8ba0d03b44 Bugfix: Clean up ThreadContext pointers when Connection is destroyed REVERT: a9e16da55e Merge bitcoin-core/libmultiprocess#105: types: Add Custom{Build,Read,Pass}Message hooks REVERT: ca2cfedd2b types: Add Custom{Build,Read,Pass}Message hooks REVERT: 6aca5f389b Merge bitcoin-core/libmultiprocess#104: Fix $Proxy.wrap mapping for empty structs with no fields REVERT: e4540729c9 Merge bitcoin-core/libmultiprocess#103: cmake: Fix package configuration file REVERT: 90f8b37a3b Fix $Proxy.wrap mapping for empty structs with no fields REVERT: c373a94d5b cmake: Fix package configuration file REVERT: 8b8a4766ce Merge bitcoin-core/libmultiprocess#102: doc: Document shutdown sequences better REVERT: 2c66dd5995 doc: Document shutdown sequences better REVERT: 6cbe56ef3b refactor, moveonly: order lambda move captures first REVERT: 8da0524628 Merge bitcoin-core/libmultiprocess#101: connection: run async cleanups in LIFO not FIFO order REVERT: 1f76880dbf util: Get rid of unused Discard struct REVERT: c92e90ce08 proxy-types Drop JoinPromises function REVERT: 53ee9faf84 Merge bitcoin-core/libmultiprocess#100: doc: Add various code comments and documentation REVERT: e45c482c40 Merge bitcoin-core/libmultiprocess#99: proxy-types: Fix missing space in server destroy log print REVERT: 6825523c6e connection: run async cleanups in LIFO not FIFO order REVERT: 537c645652 doc: Improve ProxyServerCustom class documentation REVERT: 0c70a0f89e proxy-types: Fix missing space in server destroy log print REVERT: e29f74e8ff Merge bitcoin-core/libmultiprocess#98: cmake: Combine installed packages REVERT: d4d9f93175 doc: Document FunctionTraits/ProxyMethodTraits classes REVERT: 78c7dd0be5 doc: Document ProxyClient construct/destroy methods REVERT: e99c0b7564 doc: Document clientInvoke/serverInvoke functions REVERT: 2098ae1b18 doc: Add comment on serverInvoke ReplaceVoid usage REVERT: a1dfb0bab4 doc: Add comments to mp.Context PassField function on updating g_thread_context REVERT: e49a925a40 doc: Add comments to mp.Context PassField function on mp.Context.thread lookup REVERT: dc9b4e6a99 cmake: Combine installed packages REVERT: 2ed1e9aedb cmake: CMakeLists.txt cleanup REVERT: 3f8483b61a Merge bitcoin-core/libmultiprocess#97: cmake: rename new packages and module introduced in #95 and #96 REVERT: c6a1d7fb6b cmake: rename new packages and module introduced in #95 and #96 REVERT: 003eb04d6d Merge bitcoin-core/libmultiprocess#96: cmake: Introduce packages REVERT: 19dea85cf2 Merge bitcoin-core/libmultiprocess#95: cmake: Introduce `LibmultiprocessMacros` module REVERT: 4e70ad4719 cmake, refactor: Rename target export files REVERT: 694b6b13e9 cmake: Configure `LibmultiprocessGen` package REVERT: 3b20e35ab8 cmake: Configure `Libmultiprocess` package REVERT: 66643d8eaa cmake, refactor: Use `target_capnp_sources` for examples REVERT: bd2dfe27b0 cmake, refactor: Use `target_capnp_sources` for `mptest` target REVERT: d9ec22f81b cmake: Add `LibmultiprocessMacros` module REVERT: 8da797c5f1 Merge bitcoin-core/libmultiprocess#93: Fix support for vector<bool> serialization with libc++ REVERT: 10fc3eda9c Fix support for vector<bool> serialization with libc++ REVERT: 7d1fee06d6 Merge bitcoin-core/libmultiprocess#91: util: Drop Bind, BindTuple, ComposeFn, GetFn, and ThrowFn helpers REVERT: 65260d1851 util: Drop Bind, BindTuple, ComposeFn, GetFn, and ThrowFn helpers REVERT: 2cbbd09d8b Merge bitcoin-core/libmultiprocess#90: pkgconfig: Use @CMAKE_INSTALL_LIBDIR@ variable REVERT: 02711958d9 Merge bitcoin-core/libmultiprocess#89: pkgconfig: Drop -std=c++17 compile flag REVERT: 0f9605b026 pkgconfig: Use @CMAKE_INSTALL_LIBDIR@ variable REVERT: 590d1e737c pkgconfig: Drop -std=c++17 compile flag REVERT: 414542f81e Merge bitcoin-core/libmultiprocess#88: Fix current deprecation warnings as of capnproto-1.0.1 REVERT: 962e681356 mpgen: Avoid deprecated SchemaParser::parseDiskFile call REVERT: e8e89dfd37 Remove deprecated kj::mvCapture calls to avoid warnings REVERT: 61d5a0e661 Merge bitcoin-core/libmultiprocess#86: Add support for vector<bool> serialization REVERT: 1c6fb04ddd Add support for vector<bool> serialization REVERT: aea56f0e2a Merge bitcoin-core/libmultiprocess#85: Remove naming requirement for std::pair/std::tuple REVERT: 3df497456b Remove naming requirement for std::pair/std::tuple REVERT: fc28a48f01 Merge #83: Introduce `clang-tidy` and optimize code REVERT: 594466ae97 clang-tidy: Fix `readability-make-member-function-const` check REVERT: 037fec47c8 clang-tidy: Fix `performance-unnecessary-value-param` check REVERT: 463bead1f3 clang-tidy: Fix `performance-inefficient-vector-operation` check REVERT: a435b24e64 clang-tidy: Fix `performance-faster-string-find` check REVERT: ae416f903f clang-tidy: Fix `modernize-use-nullptr` check REVERT: 9f86c9a0a8 clang-tidy: Fix `modernize-use-equals-default` check REVERT: 18b52c1663 clang-tidy: Fix `modernize-use-emplace` check REVERT: 1a33c35a3b clang-tidy: Fix `modernize-return-braced-init-list` check REVERT: 8dd83bbd91 clang-tidy: Suppress `bugprone-suspicious-semicolon` check warning REVERT: 5e787bfbd0 Add option to run `clang-tidy` with compiler REVERT: 74e25d2cd4 Merge #84: Avoid passing some function arguments by value REVERT: 8ef94d2e86 Avoid passing some function arguments by value REVERT: 917877afa8 Merge #79: Install Exports for custom `install-{lib,bin}` targets REVERT: 2dda7536b5 Install Exports for custom `install-{lib,bin}` targets REVERT: 54bd57fb3b Use `GNUInstallDirs` module REVERT: 1af83d1523 Merge #81: Add ReadDestTemp function to make it easier to call ReadField with less boilerplate REVERT: e66e6e82f6 Merge #82: build: Fix missing Cap'n Proto include directories REVERT: c75362392f build: Fix missing Cap'n Proto include directories REVERT: 70d108bc60 Add ReadDestTemp function to make it easier to call ReadField with less boilerplate REVERT: 7441069261 Merge #80: doc: Fix mpgen usage string REVERT: fcad5fbe53 doc: Fix mpgen usage string REVERT: ddd2cee627 Merge #78: refactor: Do not shadow `InvokeContext::connection` member REVERT: f999694daa refactor: Do not shadow `InvokeContext::connection` member REVERT: 4992b52754 Merge #74: Add `install-lib` and `install-bin` build targets REVERT: fa130db398 Add `install-bin` target REVERT: c4d26d2ddb Add `install-lib` target REVERT: bc3d166d37 Install `proxy.capnp` with `mpgen` target REVERT: f85fefff28 Merge #73: Drop unneeded include directory REVERT: 80dc922e4c Merge #72: Make `mpgen` target independent from `multiprocess` one REVERT: d321ef89e7 Merge #71: Use defined `CXX_STANDARD` for environment introspection REVERT: 331b5a6e49 Merge #70: Fix check for `pthread_threadid_np` REVERT: d36ebb9ace Drop unneeded include directory REVERT: 665d1fdc67 Make `mpgen` target independent from `multiprocess` one REVERT: 2eff5da83c Use defined `CXX_STANDARD` for environment introspection REVERT: 373d0d7823 Fix check for `pthread_threadid_np` REVERT: c6849de823 Merge #69: Fix CMake minimum required version REVERT: 6902bfd40e Fix CMake minimum required version REVERT: 49dc279926 Merge bitcoin-core/libmultiprocess#66: Fix typos REVERT: 9f4dac644a Fix typos REVERT: 7d10f3b1e3 Merge bitcoin-core/libmultiprocess#65: Fix clang "unknown warning group" errors REVERT: 680776fcc8 Fix clang "unknown warning group" errors REVERT: bc6624a5d3 Merge bitcoin-core/libmultiprocess#64: cleanup: Remove AUTORET macro and clean up PassField overrides REVERT: d2a9db9ebf Merge bitcoin-core/libmultiprocess#63: Fix mptest link error caused by missing kj-async dependency REVERT: cf7ebfe68d Replace ThreadMap Passfield override with generic count(0) override REVERT: 3f388cf064 Inline last AUTO_RETURN uses and remove macro REVERT: 41db49c7bc Consolidate PassField function to remove AUTO_RETURN uses REVERT: 1d005053b0 Replace output.init AUTO_RETURN uses with decltype(auto) REVERT: ea1a77b98b Replace AUTO_RETURN uses with decltype(auto) REVERT: 029d84fe77 Fix mptest link error caused by missing kj-async dependency REVERT: 306c8b100d Merge bitcoin-core/libmultiprocess#62: Fix clang compiler warnings REVERT: 1b638d67de Avoid delete-non-abstract-non-virtual-dtor warnings for mp::ProxyCallbackImpl REVERT: 5738b8ae09 Avoid delete-non-abstract-non-virtual-dtor warnings REVERT: 921e23e8d1 Disable clang suggest-override warnings for proxy clients REVERT: 34ce921d2d Merge bitcoin-core/libmultiprocess#58: Fix std::move compiler warning REVERT: 49004c8726 Merge bitcoin-core/libmultiprocess#57: doc/install.md: add cmake to brew install command REVERT: e386cfad52 Fix std::move compiler warning REVERT: 424d635ab1 doc/install.md: add cmake to brew install command REVERT: 8abd3daf1c Merge #55: Add doc/ folder, split up readme and add more usage documentation REVERT: 1a3dc8d263 Add documentation about interface definitions REVERT: 5539208883 Split up README.md REVERT: 805eb73e57 Merge #49: Add standalone example with 3 processes REVERT: 4b45e14aad Add standalone example with 3 processes REVERT: 17bfda9ece Merge #48: Move test/src/ files one level up REVERT: b648f2a13d Merge #47: gen.cpp: Check local includes before install includes REVERT: 8b5259c5b4 Move test/src/ files one level up REVERT: c2f866fa8d Merge #45: Comments and LogEscape REVERT: 1007bd7c2b gen.cpp: Check local includes before install includes REVERT: 22afe27d1e util: fix LogEscape bug REVERT: 89ababdd3c doc: add note on vats REVERT: 6e36f0f53c doc: fix various typos REVERT: b6e060af7b README: add kj explainer REVERT: d576d975de Merge #43: Drop hardcoded #include lines in generated files REVERT: 35d2091134 Merge #42: Support attaching custom cleanup functions to proxy client and server classes REVERT: 2ccc479f86 Drop hardcoded #include lines in generated files REVERT: ce8e8b654a Add ProxyTypeRegister typeid map REVERT: fbdaaa75aa Add cleanup callbacks to ProxyContext REVERT: 34e9b78ec1 refactor: Move connection field to ProxyContext struct REVERT: 39ad0f5eae Generate ProxyType traits for interface types REVERT: 1b4012cadd Merge #41: Avoid depending on argument default constructors REVERT: 0e97be35f9 Avoid depending on argument default constructors REVERT: 4dcd80741e Merge #40: Disable GCC suggest-override warnings for proxy clients REVERT: 05f9817c36 Disable GCC suggest-override warnings for proxy clients REVERT: 4c59977392 Merge #38: Add "extends" inherited method support REVERT: de748be4cf Add "extends" inherited method support REVERT: 9f5b835564 Merge #37: Add "make check" target to build and run tests REVERT: 037835320b Add "make check" target to build and run tests REVERT: 9d23fdd030 Merge #35: Fix README.md markdown REVERT: 4d946aa6d2 Fix README.md markdown REVERT: 5741d750a0 Merge #34: Add shared_ptr callback support REVERT: 9ce0335b26 Add comment saying how to fix clientInvoke missing Proxy.Context assert REVERT: 31b4f1be84 Add shared_ptr ownership and lifetime support REVERT: 27f8a35ec0 Add saveCallback / callbackSaved test setup REVERT: 5390a1b116 Add support for passing shared_ptrs without extending lifetime REVERT: 39bbf74a08 Add CustomReadField priority param for more flexibility and consistency with CustomBuildField REVERT: da489bef3f Fix bugs in PassField overload for callback objects passed by reference REVERT: ab4568bbbd Add test coverage for thread map and callbacks REVERT: 1d630f536d Merge #33: Fix empty exception values from bad ThrowFn declaration REVERT: c3efcae099 Fix empty exception values from bad ThrowFn declaration REVERT: 78f2f75d47 Merge #31: Unify ReadFieldNew / ReadFieldUpdate REVERT: 112f364f01 Unify ReadFieldNew / ReadFieldUpdate REVERT: c0e3a50455 Merge #25: Obliterate Boost REVERT: 10b5c69dbc Obliterate Boost REVERT: f4112b7966 Switch from C++14 to C++17 REVERT: f2ea4b91b4 Merge #30: proxy-io.h: fix missing assert.h include REVERT: e2ad13aee2 Merge #29: Update make test command in readme REVERT: fad36ab1a1 proxy-io.h: fix missing assert.h include REVERT: 4d7864560e Merge #28: CMake workarounds for ubuntu capnproto 0.6.1 compatibility REVERT: c8923eb01b Update make test command in readme REVERT: 097bce268a Merge #24: Don't print a dash if thread name is not known REVERT: a440eda4c8 Merge #23: Tell std::system_error() which function failed REVERT: b09973bf7a CMake workarounds for ubuntu capnproto 0.6.1 compatibility REVERT: 570db83ef4 Don't print a dash if thread name is not known REVERT: d6dac63584 Tell std::system_error() which function failed REVERT: 49a9637237 Merge #22: Handle fork(2) failures REVERT: 50b6a7f8c2 Merge #21: Refactor ThreadName() to improve its portability REVERT: 16ebae8225 Handle fork(2) failures REVERT: f1857e3e91 Refactor ThreadName() to improve its portability REVERT: fe76b287f7 Merge #19: Fix compilation of foo.h: include <string> REVERT: 829741ce5f Merge #18: A followup to a616312: remove unnecessary call REVERT: c92112a786 Fix compilation of foo.h: include <string> REVERT: 3b5da8fb44 A followup to a616312: remove unnecessary call REVERT: d3388da2c0 Merge #17: Avoid using boost::optional in PassField() REVERT: a616312ed8 Avoid using boost::optional in PassField() REVERT: abb3ae9ce9 Merge #16: Reduce boost usage REVERT: fb73b81b98 Change EventLoop::m_task_set to not use boost REVERT: 138ad6794a Change Field::(param and result) to not use boost REVERT: 5724a2c58a Remove boost usage from GetAnnotation() REVERT: cab9c51669 Remove unnecessary boost include REVERT: e0319f428a Merge #15: Add ListenConnections function REVERT: d519e18859 Add ListenConnections function REVERT: d24cae648a Merge #14: Add simpler ServeStream function REVERT: 710238c551 Add simpler ServeStream function REVERT: 5f425473be Merge #13: Add mpgen.mk makefile rules REVERT: b72ec472bb Add mpgen.mk makefile rules REVERT: 86d5a45b8d Merge #12: Add Eventloop void* context pointer REVERT: 2a2549cea3 Merge #11: Replace ProxyServer connection pointer with reference REVERT: 4907c5dced Add Eventloop void* context pointer REVERT: e7687dbed6 Replace ProxyServer connection pointer with reference REVERT: bd8ee26336 Merge #10: Remove #include <syscall.h> to avoid mac os build error REVERT: 4e452e9c1c Remove #include <syscall.h> to avoid mac os build error REVERT: 9cd1a5a9c1 Merge #9: Invoke capnp compile from mpgen REVERT: f89e4b32dc Invoke capnp compile from mpgen REVERT: dee0711538 Merge #8: Add Connnect/Serve/Spawn/Wait functions REVERT: 8125688f6c Merge #7: Add ProxyClientBase destroy_connection option REVERT: f324c66615 Add Connnect/Serve/Spawn/Wait functions REVERT: da73a6765f Merge #6: Explicitly request C++14 compiler REVERT: c685fa9bed Add ProxyClientBase destroy_connection option REVERT: 409fe97492 Explicitly request C++14 compiler REVERT: 45785e7f19 Merge #3: Limit LogEscape string size REVERT: 99bc4c523d Merge #2: Set mpgen rpath REVERT: 724d2f7fe3 Limit LogEscape string size REVERT: 4dcf39ffda Set mpgen rpath REVERT: cf5afd6dd9 Merge #1: Fix libmultiprocess.pc install path REVERT: 1bc076fbb9 Fix libmultiprocess.pc install path REVERT: 06e1045bab libmultiprocess initial commit git-subtree-dir: src/ipc/libmultiprocess git-subtree-split: 27ada4080964d26fed43d1c7329ba54b4c86199f
This bug is currently causing mptest "disconnecting and blocking" test to occasionally hang as reported by maflcko in bitcoin/bitcoin#33244.
The bug was actually first reported by Sjors in Sjors/bitcoin#90 (comment) and there are more details about it in #189.
The bug is caused by the "disconnecting and blocking" test triggering a disconnect right before a server IPC call returns. This results in a race between the IPC server thread and the
onDisconnecthandler in the event loop thread both trying to destroy the server'srequest_threadsProxyClient<Thread>object when the IPC call is done.There was a lack of synchronization in this case, fixed here by adding
loop->sync()various places. There were also lock order issues whereWaiter::m_mutexcould be incorrectly locked beforeEventLoop::m_mutexresulting in a deadlock.