bug: EventLoop::post() deadlocks when posted function throws #259

issue hulxv openend this issue on March 19, 2026
  1. hulxv commented at 7:46 pm on March 19, 2026: none

    Description

    EventLoop::loop() executes posted functions inside a for(;;) loop without exception safety on the cleanup path. If the posted function throws, m_post_fn is never reset to nullptr and m_cv.notify_all() is never called. The calling thread, blocked in post() waiting for m_post_fn != &fn, hangs forever.

    The cleanup code after the loop (closing file descriptors, resetting m_async_fns, notifying waiters) also runs outside any RAII guard, so all of it is skipped during stack unwinding.

    In loop():

    0if (m_post_fn) {
    1    Unlock(lock, *m_post_fn);   // exception propagates from here
    2    m_post_fn = nullptr;         // skipped
    3    m_cv.notify_all();           // skipped
    4}
    

    In post():

    0// waits forever: m_post_fn still == &fn, nobody notifies
    1m_cv.wait(lock.m_lock, [this, &fn]() { return m_post_fn != &fn; });
    

    After the loop exits via exception, ~EventLoop() hits KJ_ASSERT(m_post_fn == nullptr) and aborts. If assertions are disabled, the condition variable is destroyed while the posting thread still waits on it (undefined behavior).

    Current callers avoid this because clientInvoke captures exceptions in std::exception_ptr rather than letting them propagate. The bug is latent but violates exception safety guarantees and will break any future caller that throws from a posted function.

    Reproducer

     0#include <mp/proxy-io.h>
     1#include <mp/util.h>
     2
     3#include <cstdio>
     4#include <future>
     5#include <stdexcept>
     6#include <thread>
     7
     8int main()
     9{
    10    std::promise<mp::EventLoop*> loop_ready;
    11
    12    std::thread loop_thread([&] {
    13        mp::EventLoop loop("bugtest", [](mp::LogMessage log) {
    14            if (log.level == mp::Log::Raise)
    15                throw std::runtime_error(log.message);
    16        });
    17
    18        loop_ready.set_value(&loop);
    19
    20        try {
    21            loop.loop();
    22        } catch (const std::exception& e) {
    23            fprintf(stderr, "loop() threw: %s\n", e.what());
    24        }
    25        // ~EventLoop fires KJ_ASSERT(m_post_fn == nullptr) here
    26    });
    27
    28    mp::EventLoop* loop = loop_ready.get_future().get();
    29
    30    std::thread post_thread([&] {
    31        loop->post(kj::Function<void()>([] {
    32            throw std::runtime_error("throw from posted fn");
    33        }));
    34    });
    35
    36    post_thread.detach();
    37    loop_thread.join();
    38    return 0;
    39}
    

    Run under Helgrind:

      0$ valgrind --tool=helgrind ./post_race_test
      1
      2==276139== Helgrind, a thread error detector
      3==276139== Copyright (C) 2007-2024, and GNU GPL'd, by OpenWorks LLP et al.
      4==276139== Using Valgrind-3.25.1 and LibVEX; rerun with -h for copyright info
      5==276139== Command: ./test/post_race_test
      6==276139== 
      7==276139== ---Thread-Announcement------------------------------------------
      8==276139== 
      9==276139== Thread [#1](/bitcoin-core-multiprocess/1/) is the program's root thread
     10==276139== 
     11==276139== ---Thread-Announcement------------------------------------------
     12==276139== 
     13==276139== Thread [#2](/bitcoin-core-multiprocess/2/) was created
     14==276139==    at 0x50BF823: clone (in /usr/lib/libc.so.6)
     15==276139==    by 0x50BF980: ??? (in /usr/lib/libc.so.6)
     16==276139==    by 0x503B4ED: ??? (in /usr/lib/libc.so.6)
     17==276139==    by 0x503C16B: pthread_create (in /usr/lib/libc.so.6)
     18==276139==    by 0x4CB96A1: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (in /usr/lib/libstdc++.so.6.0.34)
     19==276139==    by 0x4008F22: std::thread::thread<main::{lambda()#1}, , void>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     20==276139==    by 0x4008D0B: main (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     21==276139== 
     22==276139== ----------------------------------------------------------------
     23==276139== 
     24==276139== Possible data race during read of size 8 at 0x51CE098 by thread [#1](/bitcoin-core-multiprocess/1/)
     25==276139== Locks held: none
     26==276139==    at 0x400CE00: std::__uniq_ptr_impl<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>::_M_ptr() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     27==276139==    by 0x400C1C1: std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>::get() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     28==276139==    by 0x400B4DD: std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>::operator*() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     29==276139==    by 0x400A9BC: std::__future_base::_State_baseV2::wait() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     30==276139==    by 0x400C861: std::__basic_future<mp::EventLoop*>::_M_get_result() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     31==276139==    by 0x400BD32: std::future<mp::EventLoop*>::get() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     32==276139==    by 0x4008D2A: main (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     33==276139== 
     34==276139== This conflicts with a previous write of size 8 by thread [#2](/bitcoin-core-multiprocess/2/)
     35==276139== Locks held: none
     36==276139==    at 0x400CED2: std::enable_if<std::__and_<std::__not_<std::__is_tuple_like<std::__future_base::_Result_base*> >, std::is_move_constructible<std::__future_base::_Result_base*>, std::is_move_assignable<std::__future_base::_Result_base*> >::value, void>::type std::swap<std::__future_base::_Result_base*>(std::__future_base::_Result_base*&, std::__future_base::_Result_base*&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     37==276139==    by 0x400C318: std::__uniq_ptr_impl<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>::swap(std::__uniq_ptr_impl<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     38==276139==    by 0x400B7D6: std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>::swap(std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     39==276139==    by 0x400ACCF: std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     40==276139==    by 0x400CE89: void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     41==276139==    by 0x400C213: std::__invoke_result<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>::type std::__invoke<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     42==276139==    by 0x400B574: std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     43==276139==    by 0x400C236: std::once_flag::_Prepare_execution::_Prepare_execution<std::call_once<void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)::{lambda()#1}>(void (std::__future_base::_State_baseV2::*&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*))::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     44==276139==  Address 0x51ce098 is 24 bytes inside a block of size 48 alloc'd
     45==276139==    at 0x488C093: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
     46==276139==    by 0x400ECB8: std::__new_allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_State_baseV2, std::allocator<void>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     47==276139==    by 0x400E3A6: std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_State_baseV2, std::allocator<void>, (__gnu_cxx::_Lock_policy)2> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_State_baseV2, std::allocator<void>, (__gnu_cxx::_Lock_policy)2> > >(std::allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_State_baseV2, std::allocator<void>, (__gnu_cxx::_Lock_policy)2> >&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     48==276139==    by 0x400D98C: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<std::__future_base::_State_baseV2, std::allocator<void>>(std::__future_base::_State_baseV2*&, std::_Sp_alloc_shared_tag<std::allocator<void> >) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     49==276139==    by 0x400D009: std::__shared_ptr<std::__future_base::_State_baseV2, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<void>>(std::_Sp_alloc_shared_tag<std::allocator<void> >) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     50==276139==    by 0x400C402: std::shared_ptr<std::__future_base::_State_baseV2>::shared_ptr<std::allocator<void>>(std::_Sp_alloc_shared_tag<std::allocator<void> >) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     51==276139==    by 0x400B8E6: std::shared_ptr<std::__future_base::_State_baseV2> std::make_shared<std::__future_base::_State_baseV2>() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     52==276139==    by 0x400BA6D: std::promise<mp::EventLoop*>::promise() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     53==276139==    by 0x4008CF0: main (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     54==276139==  Block was alloc'd by thread [#1](/bitcoin-core-multiprocess/1/)
     55==276139== 
     56==276139== ----------------------------------------------------------------
     57==276139== 
     58==276139== Possible data race during read of size 8 at 0x51CE100 by thread [#1](/bitcoin-core-multiprocess/1/)
     59==276139== Locks held: none
     60==276139==    at 0x400BD43: std::future<mp::EventLoop*>::get() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     61==276139==    by 0x4008D2A: main (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     62==276139== 
     63==276139== This conflicts with a previous write of size 8 by thread [#2](/bitcoin-core-multiprocess/2/)
     64==276139== Locks held: none
     65==276139==    at 0x400EB56: std::__future_base::_Result<mp::EventLoop*>::_M_set(mp::EventLoop*&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     66==276139==    by 0x400E8FA: std::__future_base::_State_baseV2::_Setter<mp::EventLoop*, mp::EventLoop*&&>::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     67==276139==    by 0x400E617: std::unique_ptr<std::__future_base::_Result<mp::EventLoop*>, std::__future_base::_Result_base::_Deleter> std::__invoke_impl<std::unique_ptr<std::__future_base::_Result<mp::EventLoop*>, std::__future_base::_Result_base::_Deleter>, std::__future_base::_State_baseV2::_Setter<mp::EventLoop*, mp::EventLoop*&&>&>(std::__invoke_other, std::__future_base::_State_baseV2::_Setter<mp::EventLoop*, mp::EventLoop*&&>&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     68==276139==    by 0x400DBDA: std::enable_if<is_invocable_r_v<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>, std::__future_base::_State_baseV2::_Setter<mp::EventLoop*, mp::EventLoop*&&>&>, std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> >::type std::__invoke_r<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>, std::__future_base::_State_baseV2::_Setter<mp::EventLoop*, mp::EventLoop*&&>&>(std::__future_base::_State_baseV2::_Setter<mp::EventLoop*, mp::EventLoop*&&>&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     69==276139==    by 0x400D1B9: std::_Function_handler<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> (), std::__future_base::_State_baseV2::_Setter<mp::EventLoop*, mp::EventLoop*&&> >::_M_invoke(std::_Any_data const&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     70==276139==    by 0x400B839: std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     71==276139==    by 0x400ACB1: std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     72==276139==    by 0x400CE89: void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*), std::__future_base::_State_baseV2*&&, std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     73==276139==  Address 0x51ce100 is 16 bytes inside a block of size 32 alloc'd
     74==276139==    at 0x488C093: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
     75==276139==    by 0x400BA7F: std::promise<mp::EventLoop*>::promise() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     76==276139==    by 0x4008CF0: main (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     77==276139==  Block was alloc'd by thread [#1](/bitcoin-core-multiprocess/1/)
     78==276139== 
     79==276139== ---Thread-Announcement------------------------------------------
     80==276139== 
     81==276139== Thread [#3](/bitcoin-core-multiprocess/3/) was created
     82==276139==    at 0x50BF823: clone (in /usr/lib/libc.so.6)
     83==276139==    by 0x50BF980: ??? (in /usr/lib/libc.so.6)
     84==276139==    by 0x503B4ED: ??? (in /usr/lib/libc.so.6)
     85==276139==    by 0x503C16B: pthread_create (in /usr/lib/libc.so.6)
     86==276139==    by 0x4CB96A1: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (in /usr/lib/libstdc++.so.6.0.34)
     87==276139==    by 0x40090A8: std::thread::thread<main::{lambda()#2}, , void>(main::{lambda()#2}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     88==276139==    by 0x4008D55: main (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     89==276139== 
     90==276139== ----------------------------------------------------------------
     91==276139== 
     92==276139== Possible data race during read of size 8 at 0x5DBBB58 by thread [#3](/bitcoin-core-multiprocess/3/)
     93==276139== Locks held: none
     94==276139==    at 0x4011264: mp::EventLoop::post(kj::Function<void ()>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     95==276139==    by 0x4008C75: main::{lambda()#2}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     96==276139==    by 0x4009C30: void std::__invoke_impl<void, main::{lambda()#2}>(std::__invoke_other, main::{lambda()#2}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     97==276139==    by 0x4009BAE: std::__invoke_result<main::{lambda()#2}>::type std::__invoke<main::{lambda()#2}>(main::{lambda()#2}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     98==276139==    by 0x4009B3D: void std::thread::_Invoker<std::tuple<main::{lambda()#2}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
     99==276139==    by 0x4009AF5: std::thread::_Invoker<std::tuple<main::{lambda()#2}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    100==276139==    by 0x4009A7F: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#2}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    101==276139==    by 0x4CB95A3: ??? (in /usr/lib/libstdc++.so.6.0.34)
    102==276139==    by 0x503B98A: ??? (in /usr/lib/libc.so.6)
    103==276139==    by 0x50BF833: clone (in /usr/lib/libc.so.6)
    104==276139==  Address 0x5dbbb58 is on thread [#2](/bitcoin-core-multiprocess/2/)'s stack
    105==276139==  in frame [#9](/bitcoin-core-multiprocess/9/), created by main::{lambda()#1}::operator()() const (???:)
    106==276139== 
    107==276139== ----------------------------------------------------------------
    108==276139== 
    109==276139== Thread [#2](/bitcoin-core-multiprocess/2/): Bug in libpthread: write lock granted on mutex/rwlock which is currently wr-held by a different thread
    110==276139==    at 0x4894C2A: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
    111==276139==    by 0x4014C11: std::mutex::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    112==276139==    by 0x4016614: std::unique_lock<std::mutex>::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    113==276139==    by 0x401654E: std::unique_lock<std::mutex>::unique_lock(std::mutex&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    114==276139==    by 0x4014E32: mp::Lock::Lock(mp::Mutex&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    115==276139==    by 0x4010C2F: mp::EventLoop::loop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    116==276139==    by 0x4008ACC: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    117==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    118==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    119==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    120==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    121==276139==    by 0x4009ABF: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#1}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    122==276139== 
    123==276139== ----------------------------------------------------------------
    124==276139== 
    125==276139==  Lock at 0x5DBBBA0 was first observed
    126==276139==    at 0x4894C2A: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
    127==276139==    by 0x4014C11: std::mutex::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    128==276139==    by 0x4016614: std::unique_lock<std::mutex>::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    129==276139==    by 0x401654E: std::unique_lock<std::mutex>::unique_lock(std::mutex&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    130==276139==    by 0x4014E32: mp::Lock::Lock(mp::Mutex&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    131==276139==    by 0x4010A4B: mp::EventLoop::loop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    132==276139==    by 0x4008ACC: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    133==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    134==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    135==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    136==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    137==276139==    by 0x4009ABF: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#1}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    138==276139==  Address 0x5dbbba0 is on thread [#2](/bitcoin-core-multiprocess/2/)'s stack
    139==276139==  in frame [#1](/bitcoin-core-multiprocess/1/), created by main::{lambda()#1}::operator()() const (???:)
    140==276139== 
    141==276139== Possible data race during read of size 8 at 0x5DBBB68 by thread [#2](/bitcoin-core-multiprocess/2/)
    142==276139== Locks held: none
    143==276139==    at 0x4010C37: mp::EventLoop::loop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    144==276139==    by 0x4008ACC: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    145==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    146==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    147==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    148==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    149==276139==    by 0x4009ABF: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#1}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    150==276139==    by 0x4CB95A3: ??? (in /usr/lib/libstdc++.so.6.0.34)
    151==276139==    by 0x503B98A: ??? (in /usr/lib/libc.so.6)
    152==276139==    by 0x50BF833: clone (in /usr/lib/libc.so.6)
    153==276139== 
    154==276139== This conflicts with a previous write of size 8 by thread [#3](/bitcoin-core-multiprocess/3/)
    155==276139== Locks held: 1, at address 0x5DBBBA0
    156==276139==    at 0x40112D9: mp::EventLoop::post(kj::Function<void ()>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    157==276139==    by 0x4008C75: main::{lambda()#2}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    158==276139==    by 0x4009C30: void std::__invoke_impl<void, main::{lambda()#2}>(std::__invoke_other, main::{lambda()#2}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    159==276139==    by 0x4009BAE: std::__invoke_result<main::{lambda()#2}>::type std::__invoke<main::{lambda()#2}>(main::{lambda()#2}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    160==276139==    by 0x4009B3D: void std::thread::_Invoker<std::tuple<main::{lambda()#2}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    161==276139==    by 0x4009AF5: std::thread::_Invoker<std::tuple<main::{lambda()#2}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    162==276139==    by 0x4009A7F: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#2}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    163==276139==    by 0x4CB95A3: ??? (in /usr/lib/libstdc++.so.6.0.34)
    164==276139==  Address 0x5dbbb68 is on thread [#2](/bitcoin-core-multiprocess/2/)'s stack
    165==276139==  in frame [#1](/bitcoin-core-multiprocess/1/), created by main::{lambda()#1}::operator()() const (???:)
    166==276139== 
    167==276139== ----------------------------------------------------------------
    168==276139== 
    169==276139== Thread [#2](/bitcoin-core-multiprocess/2/) unlocked lock at 0x5DBBBA0 currently held by thread [#3](/bitcoin-core-multiprocess/3/)
    170==276139==    at 0x4895369: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
    171==276139==    by 0x4014C5D: std::mutex::unlock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    172==276139==    by 0x40165C1: std::unique_lock<std::mutex>::unlock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    173==276139==    by 0x4014E4D: mp::Lock::unlock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    174==276139==    by 0x401A437: mp::UnlockGuard<mp::Lock>::UnlockGuard(mp::Lock&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    175==276139==    by 0x401803D: void mp::Unlock<mp::Lock, kj::Function<void ()>&>(mp::Lock&, kj::Function<void ()>&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    176==276139==    by 0x4010C5C: mp::EventLoop::loop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    177==276139==    by 0x4008ACC: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    178==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    179==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    180==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    181==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    182==276139==  Lock at 0x5DBBBA0 was first observed
    183==276139==    at 0x4894C2A: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
    184==276139==    by 0x4014C11: std::mutex::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    185==276139==    by 0x4016614: std::unique_lock<std::mutex>::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    186==276139==    by 0x401654E: std::unique_lock<std::mutex>::unique_lock(std::mutex&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    187==276139==    by 0x4014E32: mp::Lock::Lock(mp::Mutex&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    188==276139==    by 0x4010A4B: mp::EventLoop::loop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    189==276139==    by 0x4008ACC: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    190==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    191==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    192==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    193==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    194==276139==    by 0x4009ABF: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#1}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    195==276139==  Address 0x5dbbba0 is on thread [#2](/bitcoin-core-multiprocess/2/)'s stack
    196==276139==  in frame [#7](/bitcoin-core-multiprocess/7/), created by main::{lambda()#1}::operator()() const (???:)
    197==276139== 
    198==276139== 
    199==276139== ----------------------------------------------------------------
    200==276139== 
    201==276139== Possible data race during read of size 8 at 0x65BCC88 by thread [#2](/bitcoin-core-multiprocess/2/)
    202==276139== Locks held: none
    203==276139==    at 0x401ACD6: kj::Own<kj::Function<void ()>::Iface, decltype(nullptr)>::operator*() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    204==276139==    by 0x40181A9: kj::Function<void ()>::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    205==276139==    by 0x4018049: void mp::Unlock<mp::Lock, kj::Function<void ()>&>(mp::Lock&, kj::Function<void ()>&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    206==276139==    by 0x4010C5C: mp::EventLoop::loop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    207==276139==    by 0x4008ACC: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    208==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    209==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    210==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    211==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    212==276139==    by 0x4009ABF: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#1}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    213==276139==    by 0x4CB95A3: ??? (in /usr/lib/libstdc++.so.6.0.34)
    214==276139==    by 0x503B98A: ??? (in /usr/lib/libc.so.6)
    215==276139==  Address 0x65bcc88 is on thread [#3](/bitcoin-core-multiprocess/3/)'s stack
    216==276139==  in frame [#7](/bitcoin-core-multiprocess/7/), created by main::{lambda()#2}::operator()() const (???:)
    217==276139== 
    218==276139== ----------------------------------------------------------------
    219==276139== 
    220==276139== Possible data race during read of size 8 at 0x51CF080 by thread [#2](/bitcoin-core-multiprocess/2/)
    221==276139== Locks held: none
    222==276139==    at 0x40181AA: kj::Function<void ()>::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    223==276139==    by 0x4018049: void mp::Unlock<mp::Lock, kj::Function<void ()>&>(mp::Lock&, kj::Function<void ()>&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    224==276139==    by 0x4010C5C: mp::EventLoop::loop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    225==276139==    by 0x4008ACC: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    226==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    227==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    228==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    229==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    230==276139==    by 0x4009ABF: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#1}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    231==276139==    by 0x4CB95A3: ??? (in /usr/lib/libstdc++.so.6.0.34)
    232==276139==    by 0x503B98A: ??? (in /usr/lib/libc.so.6)
    233==276139==    by 0x50BF833: clone (in /usr/lib/libc.so.6)
    234==276139==  Address 0x51cf080 is 0 bytes inside a block of size 16 alloc'd
    235==276139==    at 0x488C093: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
    236==276139==    by 0x400929E: kj::Own<kj::Function<void ()>::Impl<main::{lambda()#2}::operator()() const::{lambda()#1}>, decltype(nullptr)> kj::heap<kj::Function<void ()>::Impl<main::{lambda()#2}::operator()() const::{lambda()#1}>, main::{lambda()#2}::operator()() const::{lambda()#1}>(main::{lambda()#2}::operator()() const::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    237==276139==    by 0x4008FE9: kj::Function<void ()>::Function<main::{lambda()#2}::operator()() const::{lambda()#1}>(main::{lambda()#2}::operator()() const::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    238==276139==    by 0x4008C66: main::{lambda()#2}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    239==276139==    by 0x4009C30: void std::__invoke_impl<void, main::{lambda()#2}>(std::__invoke_other, main::{lambda()#2}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    240==276139==    by 0x4009BAE: std::__invoke_result<main::{lambda()#2}>::type std::__invoke<main::{lambda()#2}>(main::{lambda()#2}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    241==276139==    by 0x4009B3D: void std::thread::_Invoker<std::tuple<main::{lambda()#2}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    242==276139==    by 0x4009AF5: std::thread::_Invoker<std::tuple<main::{lambda()#2}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    243==276139==    by 0x4009A7F: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#2}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    244==276139==    by 0x4CB95A3: ??? (in /usr/lib/libstdc++.so.6.0.34)
    245==276139==    by 0x503B98A: ??? (in /usr/lib/libc.so.6)
    246==276139==    by 0x50BF833: clone (in /usr/lib/libc.so.6)
    247==276139==  Block was alloc'd by thread [#3](/bitcoin-core-multiprocess/3/)
    248==276139== 
    249==276139== ----------------------------------------------------------------
    250==276139== 
    251==276139== Thread [#2](/bitcoin-core-multiprocess/2/): Bug in libpthread: write lock granted on mutex/rwlock which is currently wr-held by a different thread
    252==276139==    at 0x4894C2A: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
    253==276139==    by 0x4014C11: std::mutex::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    254==276139==    by 0x4016614: std::unique_lock<std::mutex>::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    255==276139==    by 0x4014E69: mp::Lock::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    256==276139==    by 0x401A456: mp::UnlockGuard<mp::Lock>::~UnlockGuard() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    257==276139==    by 0x4018075: void mp::Unlock<mp::Lock, kj::Function<void ()>&>(mp::Lock&, kj::Function<void ()>&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    258==276139==    by 0x4010C5C: mp::EventLoop::loop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    259==276139==    by 0x4008ACC: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    260==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    261==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    262==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    263==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    264==276139== 
    265==276139== ----------------------------------------------------------------
    266==276139== 
    267==276139== Thread [#2](/bitcoin-core-multiprocess/2/) unlocked lock at 0x5DBBBA0 currently held by thread [#3](/bitcoin-core-multiprocess/3/)
    268==276139==    at 0x4895369: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
    269==276139==    by 0x4014C5D: std::mutex::unlock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    270==276139==    by 0x40165C1: std::unique_lock<std::mutex>::unlock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    271==276139==    by 0x401657D: std::unique_lock<std::mutex>::~unique_lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    272==276139==    by 0x4015D49: mp::Lock::~Lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    273==276139==    by 0x4011005: mp::EventLoop::loop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    274==276139==    by 0x4008ACC: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    275==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    276==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    277==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    278==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    279==276139==    by 0x4009ABF: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#1}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    280==276139==  Lock at 0x5DBBBA0 was first observed
    281==276139==    at 0x4894C2A: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
    282==276139==    by 0x4014C11: std::mutex::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    283==276139==    by 0x4016614: std::unique_lock<std::mutex>::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    284==276139==    by 0x401654E: std::unique_lock<std::mutex>::unique_lock(std::mutex&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    285==276139==    by 0x4014E32: mp::Lock::Lock(mp::Mutex&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    286==276139==    by 0x4010A4B: mp::EventLoop::loop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    287==276139==    by 0x4008ACC: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    288==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    289==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    290==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    291==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    292==276139==    by 0x4009ABF: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#1}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    293==276139==  Address 0x5dbbba0 is on thread [#2](/bitcoin-core-multiprocess/2/)'s stack
    294==276139==  in frame [#6](/bitcoin-core-multiprocess/6/), created by main::{lambda()#1}::operator()() const (???:)
    295==276139== 
    296==276139== 
    297loop() threw: throw from posted fn
    298==276139== ----------------------------------------------------------------
    299==276139== 
    300==276139==  Lock at 0x5DBBBA0 was first observed
    301==276139==    at 0x4894C2A: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
    302==276139==    by 0x4014C11: std::mutex::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    303==276139==    by 0x4016614: std::unique_lock<std::mutex>::lock() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    304==276139==    by 0x401654E: std::unique_lock<std::mutex>::unique_lock(std::mutex&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    305==276139==    by 0x4014E32: mp::Lock::Lock(mp::Mutex&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    306==276139==    by 0x4010A4B: mp::EventLoop::loop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    307==276139==    by 0x4008ACC: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    308==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    309==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    310==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    311==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    312==276139==    by 0x4009ABF: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#1}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    313==276139==  Address 0x5dbbba0 is on thread [#2](/bitcoin-core-multiprocess/2/)'s stack
    314==276139==  in frame [#2](/bitcoin-core-multiprocess/2/), created by main::{lambda()#1}::operator()() const (???:)
    315==276139== 
    316==276139== Possible data race during read of size 8 at 0x5DBBB68 by thread [#2](/bitcoin-core-multiprocess/2/)
    317==276139== Locks held: none
    318==276139==    at 0x4017725: kj::_::DebugComparison<kj::Function<void ()>*&, decltype(nullptr)> kj::_::DebugExpression<kj::Function<void ()>*&>::operator==<decltype(nullptr)>(decltype(nullptr)&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    319==276139==    by 0x40104BF: mp::EventLoop::~EventLoop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    320==276139==    by 0x4008ADB: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    321==276139==    by 0x4009C6D: void std::__invoke_impl<void, main::{lambda()#1}>(std::__invoke_other, main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    322==276139==    by 0x4009BF3: std::__invoke_result<main::{lambda()#1}>::type std::__invoke<main::{lambda()#1}>(main::{lambda()#1}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    323==276139==    by 0x4009B69: void std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    324==276139==    by 0x4009B11: std::thread::_Invoker<std::tuple<main::{lambda()#1}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    325==276139==    by 0x4009ABF: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#1}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    326==276139==    by 0x4CB95A3: ??? (in /usr/lib/libstdc++.so.6.0.34)
    327==276139==    by 0x503B98A: ??? (in /usr/lib/libc.so.6)
    328==276139==    by 0x50BF833: clone (in /usr/lib/libc.so.6)
    329==276139== 
    330==276139== This conflicts with a previous write of size 8 by thread [#3](/bitcoin-core-multiprocess/3/)
    331==276139== Locks held: 1, at address 0x5DBBBA0
    332==276139==    at 0x40112D9: mp::EventLoop::post(kj::Function<void ()>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    333==276139==    by 0x4008C75: main::{lambda()#2}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    334==276139==    by 0x4009C30: void std::__invoke_impl<void, main::{lambda()#2}>(std::__invoke_other, main::{lambda()#2}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    335==276139==    by 0x4009BAE: std::__invoke_result<main::{lambda()#2}>::type std::__invoke<main::{lambda()#2}>(main::{lambda()#2}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    336==276139==    by 0x4009B3D: void std::thread::_Invoker<std::tuple<main::{lambda()#2}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    337==276139==    by 0x4009AF5: std::thread::_Invoker<std::tuple<main::{lambda()#2}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    338==276139==    by 0x4009A7F: std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::{lambda()#2}> > >::_M_run() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    339==276139==    by 0x4CB95A3: ??? (in /usr/lib/libstdc++.so.6.0.34)
    340==276139==  Address 0x5dbbb68 is on thread [#2](/bitcoin-core-multiprocess/2/)'s stack
    341==276139==  in frame [#2](/bitcoin-core-multiprocess/2/), created by main::{lambda()#1}::operator()() const (???:)
    342==276139== 
    343terminate called after throwing an instance of 'kj::ExceptionImpl'
    344  what():  mp/proxy.cpp:216: failed: expected m_post_fn == nullptr [65bcc80 == nullptr]
    345stack: 401052d 4008adb 4009c6d 4009bf3 4009b69 4009b11 4009abf 4cb95a3 503b98a 50bf833
    346==276139== 
    347==276139== Process terminating with default action of signal 6 (SIGABRT): dumping core
    348==276139==    at 0x503D90C: ??? (in /usr/lib/libc.so.6)
    349==276139==    by 0x4FE339F: raise (in /usr/lib/libc.so.6)
    350==276139==    by 0x4FCA579: abort (in /usr/lib/libc.so.6)
    351==276139==    by 0x4C6BBF5: ??? (in /usr/lib/libstdc++.so.6.0.34)
    352==276139==    by 0x4C85EB9: ??? (in /usr/lib/libstdc++.so.6.0.34)
    353==276139==    by 0x4C6B5D8: std::terminate() (in /usr/lib/libstdc++.so.6.0.34)
    354==276139==    by 0x4C86175: __cxa_throw (in /usr/lib/libstdc++.so.6.0.34)
    355==276139==    by 0x4B65249: ??? (in /usr/lib/libkj.so.1.2.0)
    356==276139==    by 0x4B713E2: kj::throwFatalException(kj::Exception&&, unsigned int) (in /usr/lib/libkj.so.1.2.0)
    357==276139==    by 0x4B7146A: kj::_::Debug::Fault::fatal() (in /usr/lib/libkj.so.1.2.0)
    358==276139==    by 0x401052D: mp::EventLoop::~EventLoop() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    359==276139==    by 0x4008ADB: main::{lambda()#1}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    360==276139== ----------------------------------------------------------------
    361==276139== 
    362==276139== Thread [#3](/bitcoin-core-multiprocess/3/): Exiting thread still holds 1 lock
    363==276139==    at 0x5043FE2: ??? (in /usr/lib/libc.so.6)
    364==276139==    by 0x503816B: ??? (in /usr/lib/libc.so.6)
    365==276139==    by 0x50387DB: ??? (in /usr/lib/libc.so.6)
    366==276139==    by 0x503AE9D: pthread_cond_wait (in /usr/lib/libc.so.6)
    367==276139==    by 0x4CAEEA0: std::condition_variable::wait(std::unique_lock<std::mutex>&) (in /usr/lib/libstdc++.so.6.0.34)
    368==276139==    by 0x4013150: void std::condition_variable::wait<mp::EventLoop::post(kj::Function<void ()>)::{lambda()#3}>(std::unique_lock<std::mutex>&, mp::EventLoop::post(kj::Function<void ()>)::{lambda()#3}) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    369==276139==    by 0x4011323: mp::EventLoop::post(kj::Function<void ()>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    370==276139==    by 0x4008C75: main::{lambda()#2}::operator()() const (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    371==276139==    by 0x4009C30: void std::__invoke_impl<void, main::{lambda()#2}>(std::__invoke_other, main::{lambda()#2}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    372==276139==    by 0x4009BAE: std::__invoke_result<main::{lambda()#2}>::type std::__invoke<main::{lambda()#2}>(main::{lambda()#2}&&) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    373==276139==    by 0x4009B3D: void std::thread::_Invoker<std::tuple<main::{lambda()#2}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    374==276139==    by 0x4009AF5: std::thread::_Invoker<std::tuple<main::{lambda()#2}> >::operator()() (in /home/mohamed/dev/libmultiprocess/build/test/post_race_test)
    375==276139== 
    376==276139== 
    377==276139== Use --history-level=approx or =none to gain increased speed, at
    378==276139== the cost of reduced accuracy of conflicting-access information
    379==276139== For lists of detected and suppressed errors, rerun with: -s
    380==276139== ERROR SUMMARY: 13 errors from 12 contexts (suppressed: 30 from 22)
    381[1]    276139 IOT instruction (core dumped)  valgrind --tool=helgrind ./test/post_race_test
    
  2. Sjors commented at 1:06 pm on March 20, 2026: member
    I assume #249 doesn’t (accidentally) prevent this?
  3. hulxv commented at 9:44 pm on March 20, 2026: none

    I assume #249 doesn’t (accidentally) prevent this?

    no, it doesn’t. it solves different issues. the same deadlocks happen when I tried it with its changes.

  4. ryanofsky commented at 7:03 pm on March 23, 2026: collaborator
    I’m not sure this is a bug exactly, but I think it’s possible behavior could be improved here. Left some suggestions in the linked PR #260.

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin-core/libmultiprocess. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-03-29 21:30 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me