/tmp/bitcoin/src/ipc/libmultiprocess/include/mp/type-context.h
Line | Count | Source |
1 | | // Copyright (c) The Bitcoin Core developers |
2 | | // Distributed under the MIT software license, see the accompanying |
3 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | | |
5 | | #ifndef MP_PROXY_TYPE_CONTEXT_H |
6 | | #define MP_PROXY_TYPE_CONTEXT_H |
7 | | |
8 | | #include <mp/proxy-io.h> |
9 | | #include <mp/util.h> |
10 | | |
11 | | #include <kj/string.h> |
12 | | |
13 | | namespace mp { |
14 | | template <typename Output> |
15 | | void CustomBuildField(TypeList<>, |
16 | | Priority<1>, |
17 | | ClientInvokeContext& invoke_context, |
18 | | Output&& output, |
19 | | typename std::enable_if<std::is_same<decltype(output.get()), Context::Builder>::value>::type* enable = nullptr) |
20 | 26 | { |
21 | 26 | auto& connection = invoke_context.connection; |
22 | 26 | auto& thread_context = invoke_context.thread_context; |
23 | | |
24 | | // Create local Thread::Server object corresponding to the current thread |
25 | | // and pass a Thread::Client reference to it in the Context.callbackThread |
26 | | // field so the function being called can make callbacks to this thread. |
27 | | // Also store the Thread::Client reference in the callback_threads map so |
28 | | // future calls over this connection can reuse it. |
29 | 26 | auto [callback_thread, _]{SetThread( |
30 | 26 | GuardedRef{thread_context.waiter->m_mutex, thread_context.callback_threads}, &connection, |
31 | 26 | [&] { return connection.m_threads.add(kj::heap<ProxyServer<Thread>>(connection, thread_context, std::thread{})); })};void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Line | Count | Source | 31 | 6 | [&] { return connection.m_threads.add(kj::heap<ProxyServer<Thread>>(connection, thread_context, std::thread{})); })}; |
Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Line | Count | Source | 31 | 4 | [&] { return connection.m_threads.add(kj::heap<ProxyServer<Thread>>(connection, thread_context, std::thread{})); })}; |
Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::rpc_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::rpc_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda'()::operator()() const |
32 | | |
33 | | // Call remote ThreadMap.makeThread function so server will create a |
34 | | // dedicated worker thread to run function calls from this thread. Store the |
35 | | // Thread::Client reference it returns in the request_threads map. |
36 | 26 | auto make_request_thread{[&]{ |
37 | | // This code will only run if an IPC client call is being made for the |
38 | | // first time on this thread. After the first call, subsequent calls |
39 | | // will use the existing request thread. This code will also never run at |
40 | | // all if the current thread is a request thread created for a different |
41 | | // IPC client, because in that case PassField code (below) will have set |
42 | | // request_thread to point to the calling thread. |
43 | 10 | auto request = connection.m_thread_map.makeThreadRequest(); |
44 | 10 | request.setName(thread_context.thread_name); |
45 | 10 | return request.send().getResult(); // Nonblocking due to capnp request pipelining. |
46 | 10 | }}; void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Line | Count | Source | 36 | 6 | auto make_request_thread{[&]{ | 37 | | // This code will only run if an IPC client call is being made for the | 38 | | // first time on this thread. After the first call, subsequent calls | 39 | | // will use the existing request thread. This code will also never run at | 40 | | // all if the current thread is a request thread created for a different | 41 | | // IPC client, because in that case PassField code (below) will have set | 42 | | // request_thread to point to the calling thread. | 43 | 6 | auto request = connection.m_thread_map.makeThreadRequest(); | 44 | 6 | request.setName(thread_context.thread_name); | 45 | 6 | return request.send().getResult(); // Nonblocking due to capnp request pipelining. | 46 | 6 | }}; |
Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Line | Count | Source | 36 | 4 | auto make_request_thread{[&]{ | 37 | | // This code will only run if an IPC client call is being made for the | 38 | | // first time on this thread. After the first call, subsequent calls | 39 | | // will use the existing request thread. This code will also never run at | 40 | | // all if the current thread is a request thread created for a different | 41 | | // IPC client, because in that case PassField code (below) will have set | 42 | | // request_thread to point to the calling thread. | 43 | 4 | auto request = connection.m_thread_map.makeThreadRequest(); | 44 | 4 | request.setName(thread_context.thread_name); | 45 | 4 | return request.send().getResult(); // Nonblocking due to capnp request pipelining. | 46 | 4 | }}; |
Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::rpc_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::rpc_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*)::'lambda0'()::operator()() const |
47 | 26 | auto [request_thread, _1]{SetThread( |
48 | 26 | GuardedRef{thread_context.waiter->m_mutex, thread_context.request_threads}, |
49 | 26 | &connection, make_request_thread)}; |
50 | | |
51 | 26 | auto context = output.init(); |
52 | 26 | context.setThread(request_thread->second->m_client); |
53 | 26 | context.setCallbackThread(callback_thread->second->m_client); |
54 | 26 | } void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Line | Count | Source | 20 | 6 | { | 21 | 6 | auto& connection = invoke_context.connection; | 22 | 6 | auto& thread_context = invoke_context.thread_context; | 23 | | | 24 | | // Create local Thread::Server object corresponding to the current thread | 25 | | // and pass a Thread::Client reference to it in the Context.callbackThread | 26 | | // field so the function being called can make callbacks to this thread. | 27 | | // Also store the Thread::Client reference in the callback_threads map so | 28 | | // future calls over this connection can reuse it. | 29 | 6 | auto [callback_thread, _]{SetThread( | 30 | 6 | GuardedRef{thread_context.waiter->m_mutex, thread_context.callback_threads}, &connection, | 31 | 6 | [&] { return connection.m_threads.add(kj::heap<ProxyServer<Thread>>(connection, thread_context, std::thread{})); })}; | 32 | | | 33 | | // Call remote ThreadMap.makeThread function so server will create a | 34 | | // dedicated worker thread to run function calls from this thread. Store the | 35 | | // Thread::Client reference it returns in the request_threads map. | 36 | 6 | auto make_request_thread{[&]{ | 37 | | // This code will only run if an IPC client call is being made for the | 38 | | // first time on this thread. After the first call, subsequent calls | 39 | | // will use the existing request thread. This code will also never run at | 40 | | // all if the current thread is a request thread created for a different | 41 | | // IPC client, because in that case PassField code (below) will have set | 42 | | // request_thread to point to the calling thread. | 43 | 6 | auto request = connection.m_thread_map.makeThreadRequest(); | 44 | 6 | request.setName(thread_context.thread_name); | 45 | 6 | return request.send().getResult(); // Nonblocking due to capnp request pipelining. | 46 | 6 | }}; | 47 | 6 | auto [request_thread, _1]{SetThread( | 48 | 6 | GuardedRef{thread_context.waiter->m_mutex, thread_context.request_threads}, | 49 | 6 | &connection, make_request_thread)}; | 50 | | | 51 | 6 | auto context = output.init(); | 52 | 6 | context.setThread(request_thread->second->m_client); | 53 | 6 | context.setCallbackThread(callback_thread->second->m_client); | 54 | 6 | } |
Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::init_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Line | Count | Source | 20 | 4 | { | 21 | 4 | auto& connection = invoke_context.connection; | 22 | 4 | auto& thread_context = invoke_context.thread_context; | 23 | | | 24 | | // Create local Thread::Server object corresponding to the current thread | 25 | | // and pass a Thread::Client reference to it in the Context.callbackThread | 26 | | // field so the function being called can make callbacks to this thread. | 27 | | // Also store the Thread::Client reference in the callback_threads map so | 28 | | // future calls over this connection can reuse it. | 29 | 4 | auto [callback_thread, _]{SetThread( | 30 | 4 | GuardedRef{thread_context.waiter->m_mutex, thread_context.callback_threads}, &connection, | 31 | 4 | [&] { return connection.m_threads.add(kj::heap<ProxyServer<Thread>>(connection, thread_context, std::thread{})); })}; | 32 | | | 33 | | // Call remote ThreadMap.makeThread function so server will create a | 34 | | // dedicated worker thread to run function calls from this thread. Store the | 35 | | // Thread::Client reference it returns in the request_threads map. | 36 | 4 | auto make_request_thread{[&]{ | 37 | | // This code will only run if an IPC client call is being made for the | 38 | | // first time on this thread. After the first call, subsequent calls | 39 | | // will use the existing request thread. This code will also never run at | 40 | | // all if the current thread is a request thread created for a different | 41 | | // IPC client, because in that case PassField code (below) will have set | 42 | | // request_thread to point to the calling thread. | 43 | 4 | auto request = connection.m_thread_map.makeThreadRequest(); | 44 | 4 | request.setName(thread_context.thread_name); | 45 | 4 | return request.send().getResult(); // Nonblocking due to capnp request pipelining. | 46 | 4 | }}; | 47 | 4 | auto [request_thread, _1]{SetThread( | 48 | 4 | GuardedRef{thread_context.waiter->m_mutex, thread_context.request_threads}, | 49 | 4 | &connection, make_request_thread)}; | 50 | | | 51 | 4 | auto context = output.init(); | 52 | 4 | context.setThread(request_thread->second->m_client); | 53 | 4 | context.setCallbackThread(callback_thread->second->m_client); | 54 | 4 | } |
void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Line | Count | Source | 20 | 6 | { | 21 | 6 | auto& connection = invoke_context.connection; | 22 | 6 | auto& thread_context = invoke_context.thread_context; | 23 | | | 24 | | // Create local Thread::Server object corresponding to the current thread | 25 | | // and pass a Thread::Client reference to it in the Context.callbackThread | 26 | | // field so the function being called can make callbacks to this thread. | 27 | | // Also store the Thread::Client reference in the callback_threads map so | 28 | | // future calls over this connection can reuse it. | 29 | 6 | auto [callback_thread, _]{SetThread( | 30 | 6 | GuardedRef{thread_context.waiter->m_mutex, thread_context.callback_threads}, &connection, | 31 | 6 | [&] { return connection.m_threads.add(kj::heap<ProxyServer<Thread>>(connection, thread_context, std::thread{})); })}; | 32 | | | 33 | | // Call remote ThreadMap.makeThread function so server will create a | 34 | | // dedicated worker thread to run function calls from this thread. Store the | 35 | | // Thread::Client reference it returns in the request_threads map. | 36 | 6 | auto make_request_thread{[&]{ | 37 | | // This code will only run if an IPC client call is being made for the | 38 | | // first time on this thread. After the first call, subsequent calls | 39 | | // will use the existing request thread. This code will also never run at | 40 | | // all if the current thread is a request thread created for a different | 41 | | // IPC client, because in that case PassField code (below) will have set | 42 | | // request_thread to point to the calling thread. | 43 | 6 | auto request = connection.m_thread_map.makeThreadRequest(); | 44 | 6 | request.setName(thread_context.thread_name); | 45 | 6 | return request.send().getResult(); // Nonblocking due to capnp request pipelining. | 46 | 6 | }}; | 47 | 6 | auto [request_thread, _1]{SetThread( | 48 | 6 | GuardedRef{thread_context.waiter->m_mutex, thread_context.request_threads}, | 49 | 6 | &connection, make_request_thread)}; | 50 | | | 51 | 6 | auto context = output.init(); | 52 | 6 | context.setThread(request_thread->second->m_client); | 53 | 6 | context.setCallbackThread(callback_thread->second->m_client); | 54 | 6 | } |
void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::echo_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Line | Count | Source | 20 | 6 | { | 21 | 6 | auto& connection = invoke_context.connection; | 22 | 6 | auto& thread_context = invoke_context.thread_context; | 23 | | | 24 | | // Create local Thread::Server object corresponding to the current thread | 25 | | // and pass a Thread::Client reference to it in the Context.callbackThread | 26 | | // field so the function being called can make callbacks to this thread. | 27 | | // Also store the Thread::Client reference in the callback_threads map so | 28 | | // future calls over this connection can reuse it. | 29 | 6 | auto [callback_thread, _]{SetThread( | 30 | 6 | GuardedRef{thread_context.waiter->m_mutex, thread_context.callback_threads}, &connection, | 31 | 6 | [&] { return connection.m_threads.add(kj::heap<ProxyServer<Thread>>(connection, thread_context, std::thread{})); })}; | 32 | | | 33 | | // Call remote ThreadMap.makeThread function so server will create a | 34 | | // dedicated worker thread to run function calls from this thread. Store the | 35 | | // Thread::Client reference it returns in the request_threads map. | 36 | 6 | auto make_request_thread{[&]{ | 37 | | // This code will only run if an IPC client call is being made for the | 38 | | // first time on this thread. After the first call, subsequent calls | 39 | | // will use the existing request thread. This code will also never run at | 40 | | // all if the current thread is a request thread created for a different | 41 | | // IPC client, because in that case PassField code (below) will have set | 42 | | // request_thread to point to the calling thread. | 43 | 6 | auto request = connection.m_thread_map.makeThreadRequest(); | 44 | 6 | request.setName(thread_context.thread_name); | 45 | 6 | return request.send().getResult(); // Nonblocking due to capnp request pipelining. | 46 | 6 | }}; | 47 | 6 | auto [request_thread, _1]{SetThread( | 48 | 6 | GuardedRef{thread_context.waiter->m_mutex, thread_context.request_threads}, | 49 | 6 | &connection, make_request_thread)}; | 50 | | | 51 | 6 | auto context = output.init(); | 52 | 6 | context.setThread(request_thread->second->m_client); | 53 | 6 | context.setCallbackThread(callback_thread->second->m_client); | 54 | 6 | } |
Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Unexecuted instantiation: void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::mining_fields::Context, 17>, capnp::Request<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) void mp::CustomBuildField<mp::StructField<mp::Accessor<mp::rpc_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>>(mp::TypeList<>, mp::Priority<1>, mp::ClientInvokeContext&, mp::StructField<mp::Accessor<mp::rpc_fields::Context, 17>, capnp::Request<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>&&, std::enable_if<std::is_same<decltype(fp2.get()), mp::Context::Builder>::value, void>::type*) Line | Count | Source | 20 | 4 | { | 21 | 4 | auto& connection = invoke_context.connection; | 22 | 4 | auto& thread_context = invoke_context.thread_context; | 23 | | | 24 | | // Create local Thread::Server object corresponding to the current thread | 25 | | // and pass a Thread::Client reference to it in the Context.callbackThread | 26 | | // field so the function being called can make callbacks to this thread. | 27 | | // Also store the Thread::Client reference in the callback_threads map so | 28 | | // future calls over this connection can reuse it. | 29 | 4 | auto [callback_thread, _]{SetThread( | 30 | 4 | GuardedRef{thread_context.waiter->m_mutex, thread_context.callback_threads}, &connection, | 31 | 4 | [&] { return connection.m_threads.add(kj::heap<ProxyServer<Thread>>(connection, thread_context, std::thread{})); })}; | 32 | | | 33 | | // Call remote ThreadMap.makeThread function so server will create a | 34 | | // dedicated worker thread to run function calls from this thread. Store the | 35 | | // Thread::Client reference it returns in the request_threads map. | 36 | 4 | auto make_request_thread{[&]{ | 37 | | // This code will only run if an IPC client call is being made for the | 38 | | // first time on this thread. After the first call, subsequent calls | 39 | | // will use the existing request thread. This code will also never run at | 40 | | // all if the current thread is a request thread created for a different | 41 | | // IPC client, because in that case PassField code (below) will have set | 42 | | // request_thread to point to the calling thread. | 43 | 4 | auto request = connection.m_thread_map.makeThreadRequest(); | 44 | 4 | request.setName(thread_context.thread_name); | 45 | 4 | return request.send().getResult(); // Nonblocking due to capnp request pipelining. | 46 | 4 | }}; | 47 | 4 | auto [request_thread, _1]{SetThread( | 48 | 4 | GuardedRef{thread_context.waiter->m_mutex, thread_context.request_threads}, | 49 | 4 | &connection, make_request_thread)}; | 50 | | | 51 | 4 | auto context = output.init(); | 52 | 4 | context.setThread(request_thread->second->m_client); | 53 | 4 | context.setCallbackThread(callback_thread->second->m_client); | 54 | 4 | } |
|
55 | | |
56 | | //! PassField override for mp.Context arguments. Return asynchronously and call |
57 | | //! function on other thread found in context. |
58 | | template <typename Accessor, typename ServerContext, typename Fn, typename... Args> |
59 | | auto PassField(Priority<1>, TypeList<>, ServerContext& server_context, const Fn& fn, Args&&... args) -> |
60 | | typename std::enable_if< |
61 | | std::is_same<decltype(Accessor::get(server_context.call_context.getParams())), Context::Reader>::value, |
62 | | kj::Promise<typename ServerContext::CallContext>>::type |
63 | 26 | { |
64 | 26 | auto& server = server_context.proxy_server; |
65 | 26 | EventLoop& loop = *server.m_context.loop; |
66 | 26 | int req = server_context.req; |
67 | | // Keep a reference to the ProxyServer instance by assigning it to the self |
68 | | // variable. ProxyServer instances are reference-counted and if the client |
69 | | // drops its reference and the IPC call is canceled, this variable keeps the |
70 | | // instance alive until the method finishes executing. The self variable |
71 | | // needs to be destroyed on the event loop thread so it is freed in a sync() |
72 | | // call below. |
73 | 26 | auto self = server.thisCap(); |
74 | 26 | auto invoke = [self = kj::mv(self), call_context = kj::mv(server_context.call_context), &server, &loop, req, fn, args...](CancelMonitor& cancel_monitor) mutable { |
75 | 26 | MP_LOG(loop, Log::Debug) << "IPC server executing request #" << req; |
76 | 26 | if (loop.testing_hook_async_request_start) loop.testing_hook_async_request_start(); |
77 | 26 | KJ_DEFER(if (loop.testing_hook_async_request_done) loop.testing_hook_async_request_done()); |
78 | 26 | ServerContext server_context{server, call_context, req}; |
79 | | // Before invoking the function, store a reference to the |
80 | | // callbackThread provided by the client in the |
81 | | // thread_local.request_threads map. This way, if this |
82 | | // server thread needs to execute any RPCs that call back to |
83 | | // the client, they will happen on the same client thread |
84 | | // that is waiting for this function, just like what would |
85 | | // happen if this were a normal function call made on the |
86 | | // local stack. |
87 | | // |
88 | | // If the request_threads map already has an entry for this |
89 | | // connection, it will be left unchanged, and it indicates |
90 | | // that the current thread is an RPC client thread which is |
91 | | // in the middle of an RPC call, and the current RPC call is |
92 | | // a nested call from the remote thread handling that RPC |
93 | | // call. In this case, the callbackThread value should point |
94 | | // to the same thread already in the map, so there is no |
95 | | // need to update the map. |
96 | 26 | auto& thread_context = g_thread_context; |
97 | 26 | auto& request_threads = thread_context.request_threads; |
98 | 26 | ConnThread request_thread; |
99 | 26 | bool inserted{false}; |
100 | 26 | Mutex cancel_mutex; |
101 | 26 | Lock cancel_lock{cancel_mutex}; |
102 | 26 | server_context.cancel_lock = &cancel_lock; |
103 | 26 | loop.sync([&] { |
104 | | // Detect request being canceled before it executes. |
105 | 26 | if (cancel_monitor.m_canceled) { |
106 | 0 | server_context.request_canceled = true; |
107 | 0 | return; |
108 | 0 | } |
109 | | // Detect request being canceled while it executes. |
110 | 26 | assert(!cancel_monitor.m_on_cancel); |
111 | 26 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { |
112 | 0 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; |
113 | | // Lock cancel_mutex here to block the event loop |
114 | | // thread and prevent it from deleting the request's |
115 | | // params and response structs while the execution |
116 | | // thread is accessing them. Because this lock is |
117 | | // released before the event loop thread does delete |
118 | | // the structs, the mutex does not provide any |
119 | | // protection from the event loop deleting the |
120 | | // structs _before_ the execution thread acquires |
121 | | // it. So in addition to locking the mutex, the |
122 | | // execution thread always checks request_canceled |
123 | | // as well before accessing the structs. |
124 | 0 | Lock cancel_lock{cancel_mutex}; |
125 | 0 | server_context.request_canceled = true; |
126 | 0 | }; Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<node::BlockCreateOptions const&, bool>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<node::BlockCreateOptions const&, bool>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<node::BlockWaitOptions>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<node::BlockWaitOptions>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::rpc_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::rpc_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>>, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>&, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>> const&, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>&, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda'()::operator()() const |
127 | | // Update requests_threads map if not canceled. We know |
128 | | // the request is not canceled currently because |
129 | | // cancel_monitor.m_canceled was checked above and this |
130 | | // code is running on the event loop thread. |
131 | 26 | std::tie(request_thread, inserted) = SetThread( |
132 | 26 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, |
133 | 26 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); });std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Line | Count | Source | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); |
Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Line | Count | Source | 133 | 4 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); |
Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<node::BlockCreateOptions const&, bool>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<node::BlockCreateOptions const&, bool>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<node::BlockWaitOptions>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<node::BlockWaitOptions>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const std::enable_if<std::is_same<decltype(mp::Accessor<mp::rpc_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::rpc_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>>, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>&, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>> const&, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Line | Count | Source | 133 | 4 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); |
std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Line | Count | Source | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); |
std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>&, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const::'lambda0'()::operator()() const Line | Count | Source | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); |
|
134 | 26 | }); std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Line | Count | Source | 103 | 6 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 6 | if (cancel_monitor.m_canceled) { | 106 | 0 | server_context.request_canceled = true; | 107 | 0 | return; | 108 | 0 | } | 109 | | // Detect request being canceled while it executes. | 110 | 6 | assert(!cancel_monitor.m_on_cancel); | 111 | 6 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 6 | Lock cancel_lock{cancel_mutex}; | 125 | 6 | server_context.request_canceled = true; | 126 | 6 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 6 | std::tie(request_thread, inserted) = SetThread( | 132 | 6 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 6 | }); |
Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Line | Count | Source | 103 | 4 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 4 | if (cancel_monitor.m_canceled) { | 106 | 0 | server_context.request_canceled = true; | 107 | 0 | return; | 108 | 0 | } | 109 | | // Detect request being canceled while it executes. | 110 | 4 | assert(!cancel_monitor.m_on_cancel); | 111 | 4 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 4 | Lock cancel_lock{cancel_mutex}; | 125 | 4 | server_context.request_canceled = true; | 126 | 4 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 4 | std::tie(request_thread, inserted) = SetThread( | 132 | 4 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 4 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 4 | }); |
Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<node::BlockCreateOptions const&, bool>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<node::BlockCreateOptions const&, bool>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<node::BlockWaitOptions>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<node::BlockWaitOptions>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const std::enable_if<std::is_same<decltype(mp::Accessor<mp::rpc_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::rpc_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>>, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>&, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>> const&, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Line | Count | Source | 103 | 4 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 4 | if (cancel_monitor.m_canceled) { | 106 | 0 | server_context.request_canceled = true; | 107 | 0 | return; | 108 | 0 | } | 109 | | // Detect request being canceled while it executes. | 110 | 4 | assert(!cancel_monitor.m_on_cancel); | 111 | 4 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 4 | Lock cancel_lock{cancel_mutex}; | 125 | 4 | server_context.request_canceled = true; | 126 | 4 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 4 | std::tie(request_thread, inserted) = SetThread( | 132 | 4 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 4 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 4 | }); |
std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Line | Count | Source | 103 | 6 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 6 | if (cancel_monitor.m_canceled) { | 106 | 0 | server_context.request_canceled = true; | 107 | 0 | return; | 108 | 0 | } | 109 | | // Detect request being canceled while it executes. | 110 | 6 | assert(!cancel_monitor.m_on_cancel); | 111 | 6 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 6 | Lock cancel_lock{cancel_mutex}; | 125 | 6 | server_context.request_canceled = true; | 126 | 6 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 6 | std::tie(request_thread, inserted) = SetThread( | 132 | 6 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 6 | }); |
std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>&, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&)::'lambda0'()::operator()() const Line | Count | Source | 103 | 6 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 6 | if (cancel_monitor.m_canceled) { | 106 | 0 | server_context.request_canceled = true; | 107 | 0 | return; | 108 | 0 | } | 109 | | // Detect request being canceled while it executes. | 110 | 6 | assert(!cancel_monitor.m_on_cancel); | 111 | 6 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 6 | Lock cancel_lock{cancel_mutex}; | 125 | 6 | server_context.request_canceled = true; | 126 | 6 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 6 | std::tie(request_thread, inserted) = SetThread( | 132 | 6 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 6 | }); |
|
135 | | |
136 | | // If an entry was inserted into the request_threads map, |
137 | | // remove it after calling fn.invoke. If an entry was not |
138 | | // inserted, one already existed, meaning this must be a |
139 | | // recursive call (IPC call calling back to the caller which |
140 | | // makes another IPC call), so avoid modifying the map. |
141 | 26 | const bool erase_thread{inserted}; |
142 | 26 | KJ_DEFER( |
143 | | // Release the cancel lock before calling loop->sync and |
144 | | // waiting for the event loop thread, because if a |
145 | | // cancellation happened, it needs to run the on_cancel |
146 | | // callback above. It's safe to release cancel_lock at |
147 | | // this point because the fn.invoke() call below will be |
148 | | // finished and no longer accessing the params or |
149 | | // results structs. |
150 | 26 | cancel_lock.m_lock.unlock(); |
151 | | // Erase the request_threads entry on the event loop |
152 | | // thread with loop->sync(), so if the connection is |
153 | | // broken there is not a race between this thread and |
154 | | // the disconnect handler trying to destroy the thread |
155 | | // client object. |
156 | 26 | loop.sync([&] { |
157 | | // Clear cancellation callback. At this point the |
158 | | // method invocation finished and the result is |
159 | | // either being returned, or discarded if a |
160 | | // cancellation happened. So we do not need to be |
161 | | // notified of cancellations after this point. Also |
162 | | // we do not want to be notified because |
163 | | // cancel_mutex and server_context could be out of |
164 | | // scope when it happens. |
165 | 26 | cancel_monitor.m_on_cancel = nullptr; |
166 | 26 | auto self_dispose{kj::mv(self)}; |
167 | 26 | if (erase_thread) { |
168 | | // Look up the thread again without using existing |
169 | | // iterator since entry may no longer be there after |
170 | | // a disconnect. Destroy node after releasing |
171 | | // Waiter::m_mutex, so the ProxyClient<Thread> |
172 | | // destructor is able to use EventLoop::mutex |
173 | | // without violating lock order. |
174 | 26 | ConnThreads::node_type removed; |
175 | 26 | { |
176 | 26 | Lock lock(thread_context.waiter->m_mutex); |
177 | 26 | removed = request_threads.extract(server.m_context.connection); |
178 | 26 | } |
179 | 26 | } |
180 | 26 | }); |
181 | 26 | ); |
182 | 26 | if (server_context.request_canceled) { |
183 | 0 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled before it could be executed"; |
184 | 26 | } else KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]{ |
185 | 26 | try { |
186 | 26 | fn.invoke(server_context, args...); |
187 | 26 | } catch (const InterruptException& e) { |
188 | 26 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " interrupted (" << e.what() << ")"; |
189 | 26 | } |
190 | 26 | })) { |
191 | 0 | MP_LOG(loop, Log::Error) << "IPC server request #" << req << " uncaught exception (" << kj::str(*exception).cStr() << ")"; |
192 | 0 | kj::throwRecoverableException(kj::mv(*exception)); |
193 | 0 | } |
194 | 26 | return call_context; |
195 | | // End of scope: if KJ_DEFER was reached, it runs here |
196 | 26 | }; std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Line | Count | Source | 74 | 6 | auto invoke = [self = kj::mv(self), call_context = kj::mv(server_context.call_context), &server, &loop, req, fn, args...](CancelMonitor& cancel_monitor) mutable { | 75 | 6 | MP_LOG(loop, Log::Debug) << "IPC server executing request #" << req; | 76 | 6 | if (loop.testing_hook_async_request_start) loop.testing_hook_async_request_start(); | 77 | 6 | KJ_DEFER(if (loop.testing_hook_async_request_done) loop.testing_hook_async_request_done()); | 78 | 6 | ServerContext server_context{server, call_context, req}; | 79 | | // Before invoking the function, store a reference to the | 80 | | // callbackThread provided by the client in the | 81 | | // thread_local.request_threads map. This way, if this | 82 | | // server thread needs to execute any RPCs that call back to | 83 | | // the client, they will happen on the same client thread | 84 | | // that is waiting for this function, just like what would | 85 | | // happen if this were a normal function call made on the | 86 | | // local stack. | 87 | | // | 88 | | // If the request_threads map already has an entry for this | 89 | | // connection, it will be left unchanged, and it indicates | 90 | | // that the current thread is an RPC client thread which is | 91 | | // in the middle of an RPC call, and the current RPC call is | 92 | | // a nested call from the remote thread handling that RPC | 93 | | // call. In this case, the callbackThread value should point | 94 | | // to the same thread already in the map, so there is no | 95 | | // need to update the map. | 96 | 6 | auto& thread_context = g_thread_context; | 97 | 6 | auto& request_threads = thread_context.request_threads; | 98 | 6 | ConnThread request_thread; | 99 | 6 | bool inserted{false}; | 100 | 6 | Mutex cancel_mutex; | 101 | 6 | Lock cancel_lock{cancel_mutex}; | 102 | 6 | server_context.cancel_lock = &cancel_lock; | 103 | 6 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 6 | if (cancel_monitor.m_canceled) { | 106 | 6 | server_context.request_canceled = true; | 107 | 6 | return; | 108 | 6 | } | 109 | | // Detect request being canceled while it executes. | 110 | 6 | assert(!cancel_monitor.m_on_cancel); | 111 | 6 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 6 | Lock cancel_lock{cancel_mutex}; | 125 | 6 | server_context.request_canceled = true; | 126 | 6 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 6 | std::tie(request_thread, inserted) = SetThread( | 132 | 6 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 6 | }); | 135 | | | 136 | | // If an entry was inserted into the request_threads map, | 137 | | // remove it after calling fn.invoke. If an entry was not | 138 | | // inserted, one already existed, meaning this must be a | 139 | | // recursive call (IPC call calling back to the caller which | 140 | | // makes another IPC call), so avoid modifying the map. | 141 | 6 | const bool erase_thread{inserted}; | 142 | 6 | KJ_DEFER( | 143 | | // Release the cancel lock before calling loop->sync and | 144 | | // waiting for the event loop thread, because if a | 145 | | // cancellation happened, it needs to run the on_cancel | 146 | | // callback above. It's safe to release cancel_lock at | 147 | | // this point because the fn.invoke() call below will be | 148 | | // finished and no longer accessing the params or | 149 | | // results structs. | 150 | 6 | cancel_lock.m_lock.unlock(); | 151 | | // Erase the request_threads entry on the event loop | 152 | | // thread with loop->sync(), so if the connection is | 153 | | // broken there is not a race between this thread and | 154 | | // the disconnect handler trying to destroy the thread | 155 | | // client object. | 156 | 6 | loop.sync([&] { | 157 | | // Clear cancellation callback. At this point the | 158 | | // method invocation finished and the result is | 159 | | // either being returned, or discarded if a | 160 | | // cancellation happened. So we do not need to be | 161 | | // notified of cancellations after this point. Also | 162 | | // we do not want to be notified because | 163 | | // cancel_mutex and server_context could be out of | 164 | | // scope when it happens. | 165 | 6 | cancel_monitor.m_on_cancel = nullptr; | 166 | 6 | auto self_dispose{kj::mv(self)}; | 167 | 6 | if (erase_thread) { | 168 | | // Look up the thread again without using existing | 169 | | // iterator since entry may no longer be there after | 170 | | // a disconnect. Destroy node after releasing | 171 | | // Waiter::m_mutex, so the ProxyClient<Thread> | 172 | | // destructor is able to use EventLoop::mutex | 173 | | // without violating lock order. | 174 | 6 | ConnThreads::node_type removed; | 175 | 6 | { | 176 | 6 | Lock lock(thread_context.waiter->m_mutex); | 177 | 6 | removed = request_threads.extract(server.m_context.connection); | 178 | 6 | } | 179 | 6 | } | 180 | 6 | }); | 181 | 6 | ); | 182 | 6 | if (server_context.request_canceled) { | 183 | 0 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled before it could be executed"; | 184 | 6 | } else KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]{ | 185 | 6 | try { | 186 | 6 | fn.invoke(server_context, args...); | 187 | 6 | } catch (const InterruptException& e) { | 188 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " interrupted (" << e.what() << ")"; | 189 | 6 | } | 190 | 6 | })) { | 191 | 0 | MP_LOG(loop, Log::Error) << "IPC server request #" << req << " uncaught exception (" << kj::str(*exception).cStr() << ")"; | 192 | 0 | kj::throwRecoverableException(kj::mv(*exception)); | 193 | 0 | } | 194 | 6 | return call_context; | 195 | | // End of scope: if KJ_DEFER was reached, it runs here | 196 | 6 | }; |
Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Line | Count | Source | 74 | 4 | auto invoke = [self = kj::mv(self), call_context = kj::mv(server_context.call_context), &server, &loop, req, fn, args...](CancelMonitor& cancel_monitor) mutable { | 75 | 4 | MP_LOG(loop, Log::Debug) << "IPC server executing request #" << req; | 76 | 4 | if (loop.testing_hook_async_request_start) loop.testing_hook_async_request_start(); | 77 | 4 | KJ_DEFER(if (loop.testing_hook_async_request_done) loop.testing_hook_async_request_done()); | 78 | 4 | ServerContext server_context{server, call_context, req}; | 79 | | // Before invoking the function, store a reference to the | 80 | | // callbackThread provided by the client in the | 81 | | // thread_local.request_threads map. This way, if this | 82 | | // server thread needs to execute any RPCs that call back to | 83 | | // the client, they will happen on the same client thread | 84 | | // that is waiting for this function, just like what would | 85 | | // happen if this were a normal function call made on the | 86 | | // local stack. | 87 | | // | 88 | | // If the request_threads map already has an entry for this | 89 | | // connection, it will be left unchanged, and it indicates | 90 | | // that the current thread is an RPC client thread which is | 91 | | // in the middle of an RPC call, and the current RPC call is | 92 | | // a nested call from the remote thread handling that RPC | 93 | | // call. In this case, the callbackThread value should point | 94 | | // to the same thread already in the map, so there is no | 95 | | // need to update the map. | 96 | 4 | auto& thread_context = g_thread_context; | 97 | 4 | auto& request_threads = thread_context.request_threads; | 98 | 4 | ConnThread request_thread; | 99 | 4 | bool inserted{false}; | 100 | 4 | Mutex cancel_mutex; | 101 | 4 | Lock cancel_lock{cancel_mutex}; | 102 | 4 | server_context.cancel_lock = &cancel_lock; | 103 | 4 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 4 | if (cancel_monitor.m_canceled) { | 106 | 4 | server_context.request_canceled = true; | 107 | 4 | return; | 108 | 4 | } | 109 | | // Detect request being canceled while it executes. | 110 | 4 | assert(!cancel_monitor.m_on_cancel); | 111 | 4 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 4 | Lock cancel_lock{cancel_mutex}; | 125 | 4 | server_context.request_canceled = true; | 126 | 4 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 4 | std::tie(request_thread, inserted) = SetThread( | 132 | 4 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 4 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 4 | }); | 135 | | | 136 | | // If an entry was inserted into the request_threads map, | 137 | | // remove it after calling fn.invoke. If an entry was not | 138 | | // inserted, one already existed, meaning this must be a | 139 | | // recursive call (IPC call calling back to the caller which | 140 | | // makes another IPC call), so avoid modifying the map. | 141 | 4 | const bool erase_thread{inserted}; | 142 | 4 | KJ_DEFER( | 143 | | // Release the cancel lock before calling loop->sync and | 144 | | // waiting for the event loop thread, because if a | 145 | | // cancellation happened, it needs to run the on_cancel | 146 | | // callback above. It's safe to release cancel_lock at | 147 | | // this point because the fn.invoke() call below will be | 148 | | // finished and no longer accessing the params or | 149 | | // results structs. | 150 | 4 | cancel_lock.m_lock.unlock(); | 151 | | // Erase the request_threads entry on the event loop | 152 | | // thread with loop->sync(), so if the connection is | 153 | | // broken there is not a race between this thread and | 154 | | // the disconnect handler trying to destroy the thread | 155 | | // client object. | 156 | 4 | loop.sync([&] { | 157 | | // Clear cancellation callback. At this point the | 158 | | // method invocation finished and the result is | 159 | | // either being returned, or discarded if a | 160 | | // cancellation happened. So we do not need to be | 161 | | // notified of cancellations after this point. Also | 162 | | // we do not want to be notified because | 163 | | // cancel_mutex and server_context could be out of | 164 | | // scope when it happens. | 165 | 4 | cancel_monitor.m_on_cancel = nullptr; | 166 | 4 | auto self_dispose{kj::mv(self)}; | 167 | 4 | if (erase_thread) { | 168 | | // Look up the thread again without using existing | 169 | | // iterator since entry may no longer be there after | 170 | | // a disconnect. Destroy node after releasing | 171 | | // Waiter::m_mutex, so the ProxyClient<Thread> | 172 | | // destructor is able to use EventLoop::mutex | 173 | | // without violating lock order. | 174 | 4 | ConnThreads::node_type removed; | 175 | 4 | { | 176 | 4 | Lock lock(thread_context.waiter->m_mutex); | 177 | 4 | removed = request_threads.extract(server.m_context.connection); | 178 | 4 | } | 179 | 4 | } | 180 | 4 | }); | 181 | 4 | ); | 182 | 4 | if (server_context.request_canceled) { | 183 | 0 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled before it could be executed"; | 184 | 4 | } else KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]{ | 185 | 4 | try { | 186 | 4 | fn.invoke(server_context, args...); | 187 | 4 | } catch (const InterruptException& e) { | 188 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " interrupted (" << e.what() << ")"; | 189 | 4 | } | 190 | 4 | })) { | 191 | 0 | MP_LOG(loop, Log::Error) << "IPC server request #" << req << " uncaught exception (" << kj::str(*exception).cStr() << ")"; | 192 | 0 | kj::throwRecoverableException(kj::mv(*exception)); | 193 | 0 | } | 194 | 4 | return call_context; | 195 | | // End of scope: if KJ_DEFER was reached, it runs here | 196 | 4 | }; |
Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<node::BlockCreateOptions const&, bool>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<node::BlockCreateOptions const&, bool>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<node::BlockWaitOptions>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<node::BlockWaitOptions>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) std::enable_if<std::is_same<decltype(mp::Accessor<mp::rpc_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::rpc_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>>, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>&, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>> const&, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Line | Count | Source | 74 | 4 | auto invoke = [self = kj::mv(self), call_context = kj::mv(server_context.call_context), &server, &loop, req, fn, args...](CancelMonitor& cancel_monitor) mutable { | 75 | 4 | MP_LOG(loop, Log::Debug) << "IPC server executing request #" << req; | 76 | 4 | if (loop.testing_hook_async_request_start) loop.testing_hook_async_request_start(); | 77 | 4 | KJ_DEFER(if (loop.testing_hook_async_request_done) loop.testing_hook_async_request_done()); | 78 | 4 | ServerContext server_context{server, call_context, req}; | 79 | | // Before invoking the function, store a reference to the | 80 | | // callbackThread provided by the client in the | 81 | | // thread_local.request_threads map. This way, if this | 82 | | // server thread needs to execute any RPCs that call back to | 83 | | // the client, they will happen on the same client thread | 84 | | // that is waiting for this function, just like what would | 85 | | // happen if this were a normal function call made on the | 86 | | // local stack. | 87 | | // | 88 | | // If the request_threads map already has an entry for this | 89 | | // connection, it will be left unchanged, and it indicates | 90 | | // that the current thread is an RPC client thread which is | 91 | | // in the middle of an RPC call, and the current RPC call is | 92 | | // a nested call from the remote thread handling that RPC | 93 | | // call. In this case, the callbackThread value should point | 94 | | // to the same thread already in the map, so there is no | 95 | | // need to update the map. | 96 | 4 | auto& thread_context = g_thread_context; | 97 | 4 | auto& request_threads = thread_context.request_threads; | 98 | 4 | ConnThread request_thread; | 99 | 4 | bool inserted{false}; | 100 | 4 | Mutex cancel_mutex; | 101 | 4 | Lock cancel_lock{cancel_mutex}; | 102 | 4 | server_context.cancel_lock = &cancel_lock; | 103 | 4 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 4 | if (cancel_monitor.m_canceled) { | 106 | 4 | server_context.request_canceled = true; | 107 | 4 | return; | 108 | 4 | } | 109 | | // Detect request being canceled while it executes. | 110 | 4 | assert(!cancel_monitor.m_on_cancel); | 111 | 4 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 4 | Lock cancel_lock{cancel_mutex}; | 125 | 4 | server_context.request_canceled = true; | 126 | 4 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 4 | std::tie(request_thread, inserted) = SetThread( | 132 | 4 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 4 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 4 | }); | 135 | | | 136 | | // If an entry was inserted into the request_threads map, | 137 | | // remove it after calling fn.invoke. If an entry was not | 138 | | // inserted, one already existed, meaning this must be a | 139 | | // recursive call (IPC call calling back to the caller which | 140 | | // makes another IPC call), so avoid modifying the map. | 141 | 4 | const bool erase_thread{inserted}; | 142 | 4 | KJ_DEFER( | 143 | | // Release the cancel lock before calling loop->sync and | 144 | | // waiting for the event loop thread, because if a | 145 | | // cancellation happened, it needs to run the on_cancel | 146 | | // callback above. It's safe to release cancel_lock at | 147 | | // this point because the fn.invoke() call below will be | 148 | | // finished and no longer accessing the params or | 149 | | // results structs. | 150 | 4 | cancel_lock.m_lock.unlock(); | 151 | | // Erase the request_threads entry on the event loop | 152 | | // thread with loop->sync(), so if the connection is | 153 | | // broken there is not a race between this thread and | 154 | | // the disconnect handler trying to destroy the thread | 155 | | // client object. | 156 | 4 | loop.sync([&] { | 157 | | // Clear cancellation callback. At this point the | 158 | | // method invocation finished and the result is | 159 | | // either being returned, or discarded if a | 160 | | // cancellation happened. So we do not need to be | 161 | | // notified of cancellations after this point. Also | 162 | | // we do not want to be notified because | 163 | | // cancel_mutex and server_context could be out of | 164 | | // scope when it happens. | 165 | 4 | cancel_monitor.m_on_cancel = nullptr; | 166 | 4 | auto self_dispose{kj::mv(self)}; | 167 | 4 | if (erase_thread) { | 168 | | // Look up the thread again without using existing | 169 | | // iterator since entry may no longer be there after | 170 | | // a disconnect. Destroy node after releasing | 171 | | // Waiter::m_mutex, so the ProxyClient<Thread> | 172 | | // destructor is able to use EventLoop::mutex | 173 | | // without violating lock order. | 174 | 4 | ConnThreads::node_type removed; | 175 | 4 | { | 176 | 4 | Lock lock(thread_context.waiter->m_mutex); | 177 | 4 | removed = request_threads.extract(server.m_context.connection); | 178 | 4 | } | 179 | 4 | } | 180 | 4 | }); | 181 | 4 | ); | 182 | 4 | if (server_context.request_canceled) { | 183 | 0 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled before it could be executed"; | 184 | 4 | } else KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]{ | 185 | 4 | try { | 186 | 4 | fn.invoke(server_context, args...); | 187 | 4 | } catch (const InterruptException& e) { | 188 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " interrupted (" << e.what() << ")"; | 189 | 4 | } | 190 | 4 | })) { | 191 | 0 | MP_LOG(loop, Log::Error) << "IPC server request #" << req << " uncaught exception (" << kj::str(*exception).cStr() << ")"; | 192 | 0 | kj::throwRecoverableException(kj::mv(*exception)); | 193 | 0 | } | 194 | 4 | return call_context; | 195 | | // End of scope: if KJ_DEFER was reached, it runs here | 196 | 4 | }; |
std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Line | Count | Source | 74 | 6 | auto invoke = [self = kj::mv(self), call_context = kj::mv(server_context.call_context), &server, &loop, req, fn, args...](CancelMonitor& cancel_monitor) mutable { | 75 | 6 | MP_LOG(loop, Log::Debug) << "IPC server executing request #" << req; | 76 | 6 | if (loop.testing_hook_async_request_start) loop.testing_hook_async_request_start(); | 77 | 6 | KJ_DEFER(if (loop.testing_hook_async_request_done) loop.testing_hook_async_request_done()); | 78 | 6 | ServerContext server_context{server, call_context, req}; | 79 | | // Before invoking the function, store a reference to the | 80 | | // callbackThread provided by the client in the | 81 | | // thread_local.request_threads map. This way, if this | 82 | | // server thread needs to execute any RPCs that call back to | 83 | | // the client, they will happen on the same client thread | 84 | | // that is waiting for this function, just like what would | 85 | | // happen if this were a normal function call made on the | 86 | | // local stack. | 87 | | // | 88 | | // If the request_threads map already has an entry for this | 89 | | // connection, it will be left unchanged, and it indicates | 90 | | // that the current thread is an RPC client thread which is | 91 | | // in the middle of an RPC call, and the current RPC call is | 92 | | // a nested call from the remote thread handling that RPC | 93 | | // call. In this case, the callbackThread value should point | 94 | | // to the same thread already in the map, so there is no | 95 | | // need to update the map. | 96 | 6 | auto& thread_context = g_thread_context; | 97 | 6 | auto& request_threads = thread_context.request_threads; | 98 | 6 | ConnThread request_thread; | 99 | 6 | bool inserted{false}; | 100 | 6 | Mutex cancel_mutex; | 101 | 6 | Lock cancel_lock{cancel_mutex}; | 102 | 6 | server_context.cancel_lock = &cancel_lock; | 103 | 6 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 6 | if (cancel_monitor.m_canceled) { | 106 | 6 | server_context.request_canceled = true; | 107 | 6 | return; | 108 | 6 | } | 109 | | // Detect request being canceled while it executes. | 110 | 6 | assert(!cancel_monitor.m_on_cancel); | 111 | 6 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 6 | Lock cancel_lock{cancel_mutex}; | 125 | 6 | server_context.request_canceled = true; | 126 | 6 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 6 | std::tie(request_thread, inserted) = SetThread( | 132 | 6 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 6 | }); | 135 | | | 136 | | // If an entry was inserted into the request_threads map, | 137 | | // remove it after calling fn.invoke. If an entry was not | 138 | | // inserted, one already existed, meaning this must be a | 139 | | // recursive call (IPC call calling back to the caller which | 140 | | // makes another IPC call), so avoid modifying the map. | 141 | 6 | const bool erase_thread{inserted}; | 142 | 6 | KJ_DEFER( | 143 | | // Release the cancel lock before calling loop->sync and | 144 | | // waiting for the event loop thread, because if a | 145 | | // cancellation happened, it needs to run the on_cancel | 146 | | // callback above. It's safe to release cancel_lock at | 147 | | // this point because the fn.invoke() call below will be | 148 | | // finished and no longer accessing the params or | 149 | | // results structs. | 150 | 6 | cancel_lock.m_lock.unlock(); | 151 | | // Erase the request_threads entry on the event loop | 152 | | // thread with loop->sync(), so if the connection is | 153 | | // broken there is not a race between this thread and | 154 | | // the disconnect handler trying to destroy the thread | 155 | | // client object. | 156 | 6 | loop.sync([&] { | 157 | | // Clear cancellation callback. At this point the | 158 | | // method invocation finished and the result is | 159 | | // either being returned, or discarded if a | 160 | | // cancellation happened. So we do not need to be | 161 | | // notified of cancellations after this point. Also | 162 | | // we do not want to be notified because | 163 | | // cancel_mutex and server_context could be out of | 164 | | // scope when it happens. | 165 | 6 | cancel_monitor.m_on_cancel = nullptr; | 166 | 6 | auto self_dispose{kj::mv(self)}; | 167 | 6 | if (erase_thread) { | 168 | | // Look up the thread again without using existing | 169 | | // iterator since entry may no longer be there after | 170 | | // a disconnect. Destroy node after releasing | 171 | | // Waiter::m_mutex, so the ProxyClient<Thread> | 172 | | // destructor is able to use EventLoop::mutex | 173 | | // without violating lock order. | 174 | 6 | ConnThreads::node_type removed; | 175 | 6 | { | 176 | 6 | Lock lock(thread_context.waiter->m_mutex); | 177 | 6 | removed = request_threads.extract(server.m_context.connection); | 178 | 6 | } | 179 | 6 | } | 180 | 6 | }); | 181 | 6 | ); | 182 | 6 | if (server_context.request_canceled) { | 183 | 0 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled before it could be executed"; | 184 | 6 | } else KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]{ | 185 | 6 | try { | 186 | 6 | fn.invoke(server_context, args...); | 187 | 6 | } catch (const InterruptException& e) { | 188 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " interrupted (" << e.what() << ")"; | 189 | 6 | } | 190 | 6 | })) { | 191 | 0 | MP_LOG(loop, Log::Error) << "IPC server request #" << req << " uncaught exception (" << kj::str(*exception).cStr() << ")"; | 192 | 0 | kj::throwRecoverableException(kj::mv(*exception)); | 193 | 0 | } | 194 | 6 | return call_context; | 195 | | // End of scope: if KJ_DEFER was reached, it runs here | 196 | 6 | }; |
std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>&, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>&&)::'lambda'(mp::CancelMonitor&)::operator()(mp::CancelMonitor&) Line | Count | Source | 74 | 6 | auto invoke = [self = kj::mv(self), call_context = kj::mv(server_context.call_context), &server, &loop, req, fn, args...](CancelMonitor& cancel_monitor) mutable { | 75 | 6 | MP_LOG(loop, Log::Debug) << "IPC server executing request #" << req; | 76 | 6 | if (loop.testing_hook_async_request_start) loop.testing_hook_async_request_start(); | 77 | 6 | KJ_DEFER(if (loop.testing_hook_async_request_done) loop.testing_hook_async_request_done()); | 78 | 6 | ServerContext server_context{server, call_context, req}; | 79 | | // Before invoking the function, store a reference to the | 80 | | // callbackThread provided by the client in the | 81 | | // thread_local.request_threads map. This way, if this | 82 | | // server thread needs to execute any RPCs that call back to | 83 | | // the client, they will happen on the same client thread | 84 | | // that is waiting for this function, just like what would | 85 | | // happen if this were a normal function call made on the | 86 | | // local stack. | 87 | | // | 88 | | // If the request_threads map already has an entry for this | 89 | | // connection, it will be left unchanged, and it indicates | 90 | | // that the current thread is an RPC client thread which is | 91 | | // in the middle of an RPC call, and the current RPC call is | 92 | | // a nested call from the remote thread handling that RPC | 93 | | // call. In this case, the callbackThread value should point | 94 | | // to the same thread already in the map, so there is no | 95 | | // need to update the map. | 96 | 6 | auto& thread_context = g_thread_context; | 97 | 6 | auto& request_threads = thread_context.request_threads; | 98 | 6 | ConnThread request_thread; | 99 | 6 | bool inserted{false}; | 100 | 6 | Mutex cancel_mutex; | 101 | 6 | Lock cancel_lock{cancel_mutex}; | 102 | 6 | server_context.cancel_lock = &cancel_lock; | 103 | 6 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 6 | if (cancel_monitor.m_canceled) { | 106 | 6 | server_context.request_canceled = true; | 107 | 6 | return; | 108 | 6 | } | 109 | | // Detect request being canceled while it executes. | 110 | 6 | assert(!cancel_monitor.m_on_cancel); | 111 | 6 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 6 | Lock cancel_lock{cancel_mutex}; | 125 | 6 | server_context.request_canceled = true; | 126 | 6 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 6 | std::tie(request_thread, inserted) = SetThread( | 132 | 6 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 6 | }); | 135 | | | 136 | | // If an entry was inserted into the request_threads map, | 137 | | // remove it after calling fn.invoke. If an entry was not | 138 | | // inserted, one already existed, meaning this must be a | 139 | | // recursive call (IPC call calling back to the caller which | 140 | | // makes another IPC call), so avoid modifying the map. | 141 | 6 | const bool erase_thread{inserted}; | 142 | 6 | KJ_DEFER( | 143 | | // Release the cancel lock before calling loop->sync and | 144 | | // waiting for the event loop thread, because if a | 145 | | // cancellation happened, it needs to run the on_cancel | 146 | | // callback above. It's safe to release cancel_lock at | 147 | | // this point because the fn.invoke() call below will be | 148 | | // finished and no longer accessing the params or | 149 | | // results structs. | 150 | 6 | cancel_lock.m_lock.unlock(); | 151 | | // Erase the request_threads entry on the event loop | 152 | | // thread with loop->sync(), so if the connection is | 153 | | // broken there is not a race between this thread and | 154 | | // the disconnect handler trying to destroy the thread | 155 | | // client object. | 156 | 6 | loop.sync([&] { | 157 | | // Clear cancellation callback. At this point the | 158 | | // method invocation finished and the result is | 159 | | // either being returned, or discarded if a | 160 | | // cancellation happened. So we do not need to be | 161 | | // notified of cancellations after this point. Also | 162 | | // we do not want to be notified because | 163 | | // cancel_mutex and server_context could be out of | 164 | | // scope when it happens. | 165 | 6 | cancel_monitor.m_on_cancel = nullptr; | 166 | 6 | auto self_dispose{kj::mv(self)}; | 167 | 6 | if (erase_thread) { | 168 | | // Look up the thread again without using existing | 169 | | // iterator since entry may no longer be there after | 170 | | // a disconnect. Destroy node after releasing | 171 | | // Waiter::m_mutex, so the ProxyClient<Thread> | 172 | | // destructor is able to use EventLoop::mutex | 173 | | // without violating lock order. | 174 | 6 | ConnThreads::node_type removed; | 175 | 6 | { | 176 | 6 | Lock lock(thread_context.waiter->m_mutex); | 177 | 6 | removed = request_threads.extract(server.m_context.connection); | 178 | 6 | } | 179 | 6 | } | 180 | 6 | }); | 181 | 6 | ); | 182 | 6 | if (server_context.request_canceled) { | 183 | 0 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled before it could be executed"; | 184 | 6 | } else KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]{ | 185 | 6 | try { | 186 | 6 | fn.invoke(server_context, args...); | 187 | 6 | } catch (const InterruptException& e) { | 188 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " interrupted (" << e.what() << ")"; | 189 | 6 | } | 190 | 6 | })) { | 191 | 0 | MP_LOG(loop, Log::Error) << "IPC server request #" << req << " uncaught exception (" << kj::str(*exception).cStr() << ")"; | 192 | 0 | kj::throwRecoverableException(kj::mv(*exception)); | 193 | 0 | } | 194 | 6 | return call_context; | 195 | | // End of scope: if KJ_DEFER was reached, it runs here | 196 | 6 | }; |
|
197 | | |
198 | | // Lookup Thread object specified by the client. The specified thread should |
199 | | // be a local Thread::Server object, but it needs to be looked up |
200 | | // asynchronously with getLocalServer(). |
201 | 26 | const auto& params = server_context.call_context.getParams(); |
202 | 26 | Context::Reader context_arg = Accessor::get(params); |
203 | 26 | auto thread_client = context_arg.getThread(); |
204 | 26 | auto result = server.m_context.connection->m_threads.getLocalServer(thread_client) |
205 | 26 | .then([&loop, invoke = kj::mv(invoke), req](const kj::Maybe<Thread::Server&>& perhaps) mutable { |
206 | | // Assuming the thread object is found, pass it a pointer to the |
207 | | // `invoke` lambda above which will invoke the function on that |
208 | | // thread. |
209 | 26 | KJ_IF_MAYBE (thread_server, perhaps) { |
210 | 26 | auto& thread = static_cast<ProxyServer<Thread>&>(*thread_server); |
211 | 26 | MP_LOG(loop, Log::Debug) |
212 | 26 | << "IPC server post request #" << req << " {" << thread.m_thread_context.thread_name << "}"; |
213 | 26 | return thread.template post<typename ServerContext::CallContext>(std::move(invoke)); |
214 | 26 | } else { |
215 | 0 | MP_LOG(loop, Log::Error) |
216 | 0 | << "IPC server error request #" << req << ", missing thread to execute request"; |
217 | 0 | throw std::runtime_error("invalid thread handle"); |
218 | 0 | } |
219 | 26 | }); std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Line | Count | Source | 205 | 6 | .then([&loop, invoke = kj::mv(invoke), req](const kj::Maybe<Thread::Server&>& perhaps) mutable { | 206 | | // Assuming the thread object is found, pass it a pointer to the | 207 | | // `invoke` lambda above which will invoke the function on that | 208 | | // thread. | 209 | 6 | KJ_IF_MAYBE (thread_server, perhaps) { | 210 | 6 | auto& thread = static_cast<ProxyServer<Thread>&>(*thread_server); | 211 | 6 | MP_LOG(loop, Log::Debug) | 212 | 6 | << "IPC server post request #" << req << " {" << thread.m_thread_context.thread_name << "}"; | 213 | 6 | return thread.template post<typename ServerContext::CallContext>(std::move(invoke)); | 214 | 6 | } else { | 215 | 0 | MP_LOG(loop, Log::Error) | 216 | 0 | << "IPC server error request #" << req << ", missing thread to execute request"; | 217 | 0 | throw std::runtime_error("invalid thread handle"); | 218 | 0 | } | 219 | 6 | }); |
Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Line | Count | Source | 205 | 4 | .then([&loop, invoke = kj::mv(invoke), req](const kj::Maybe<Thread::Server&>& perhaps) mutable { | 206 | | // Assuming the thread object is found, pass it a pointer to the | 207 | | // `invoke` lambda above which will invoke the function on that | 208 | | // thread. | 209 | 4 | KJ_IF_MAYBE (thread_server, perhaps) { | 210 | 4 | auto& thread = static_cast<ProxyServer<Thread>&>(*thread_server); | 211 | 4 | MP_LOG(loop, Log::Debug) | 212 | 4 | << "IPC server post request #" << req << " {" << thread.m_thread_context.thread_name << "}"; | 213 | 4 | return thread.template post<typename ServerContext::CallContext>(std::move(invoke)); | 214 | 4 | } else { | 215 | 0 | MP_LOG(loop, Log::Error) | 216 | 0 | << "IPC server error request #" << req << ", missing thread to execute request"; | 217 | 0 | throw std::runtime_error("invalid thread handle"); | 218 | 0 | } | 219 | 4 | }); |
Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<node::BlockCreateOptions const&, bool>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<node::BlockCreateOptions const&, bool>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<node::BlockWaitOptions>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<node::BlockWaitOptions>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) std::enable_if<std::is_same<decltype(mp::Accessor<mp::rpc_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::rpc_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>>, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>&, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>> const&, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Line | Count | Source | 205 | 4 | .then([&loop, invoke = kj::mv(invoke), req](const kj::Maybe<Thread::Server&>& perhaps) mutable { | 206 | | // Assuming the thread object is found, pass it a pointer to the | 207 | | // `invoke` lambda above which will invoke the function on that | 208 | | // thread. | 209 | 4 | KJ_IF_MAYBE (thread_server, perhaps) { | 210 | 4 | auto& thread = static_cast<ProxyServer<Thread>&>(*thread_server); | 211 | 4 | MP_LOG(loop, Log::Debug) | 212 | 4 | << "IPC server post request #" << req << " {" << thread.m_thread_context.thread_name << "}"; | 213 | 4 | return thread.template post<typename ServerContext::CallContext>(std::move(invoke)); | 214 | 4 | } else { | 215 | 0 | MP_LOG(loop, Log::Error) | 216 | 0 | << "IPC server error request #" << req << ", missing thread to execute request"; | 217 | 0 | throw std::runtime_error("invalid thread handle"); | 218 | 0 | } | 219 | 4 | }); |
std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Line | Count | Source | 205 | 6 | .then([&loop, invoke = kj::mv(invoke), req](const kj::Maybe<Thread::Server&>& perhaps) mutable { | 206 | | // Assuming the thread object is found, pass it a pointer to the | 207 | | // `invoke` lambda above which will invoke the function on that | 208 | | // thread. | 209 | 6 | KJ_IF_MAYBE (thread_server, perhaps) { | 210 | 6 | auto& thread = static_cast<ProxyServer<Thread>&>(*thread_server); | 211 | 6 | MP_LOG(loop, Log::Debug) | 212 | 6 | << "IPC server post request #" << req << " {" << thread.m_thread_context.thread_name << "}"; | 213 | 6 | return thread.template post<typename ServerContext::CallContext>(std::move(invoke)); | 214 | 6 | } else { | 215 | 0 | MP_LOG(loop, Log::Error) | 216 | 0 | << "IPC server error request #" << req << ", missing thread to execute request"; | 217 | 0 | throw std::runtime_error("invalid thread handle"); | 218 | 0 | } | 219 | 6 | }); |
std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>&, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>&&)::'lambda'(kj::Maybe<mp::Thread::Server&> const&)::operator()(kj::Maybe<mp::Thread::Server&> const&) Line | Count | Source | 205 | 6 | .then([&loop, invoke = kj::mv(invoke), req](const kj::Maybe<Thread::Server&>& perhaps) mutable { | 206 | | // Assuming the thread object is found, pass it a pointer to the | 207 | | // `invoke` lambda above which will invoke the function on that | 208 | | // thread. | 209 | 6 | KJ_IF_MAYBE (thread_server, perhaps) { | 210 | 6 | auto& thread = static_cast<ProxyServer<Thread>&>(*thread_server); | 211 | 6 | MP_LOG(loop, Log::Debug) | 212 | 6 | << "IPC server post request #" << req << " {" << thread.m_thread_context.thread_name << "}"; | 213 | 6 | return thread.template post<typename ServerContext::CallContext>(std::move(invoke)); | 214 | 6 | } else { | 215 | 0 | MP_LOG(loop, Log::Error) | 216 | 0 | << "IPC server error request #" << req << ", missing thread to execute request"; | 217 | 0 | throw std::runtime_error("invalid thread handle"); | 218 | 0 | } | 219 | 6 | }); |
|
220 | | // Use connection m_canceler object to cancel the result promise if the |
221 | | // connection is destroyed. (By default Cap'n Proto does not cancel requests |
222 | | // on disconnect, since it's possible clients might want to make requests |
223 | | // and immediately disconnect without waiting for results, but not want the |
224 | | // requests to be canceled.) |
225 | 26 | return server.m_context.connection->m_canceler.wrap(kj::mv(result)); |
226 | 26 | } std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeEchoParams, ipc::capnp::messages::Init::MakeEchoResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&) Line | Count | Source | 63 | 6 | { | 64 | 6 | auto& server = server_context.proxy_server; | 65 | 6 | EventLoop& loop = *server.m_context.loop; | 66 | 6 | int req = server_context.req; | 67 | | // Keep a reference to the ProxyServer instance by assigning it to the self | 68 | | // variable. ProxyServer instances are reference-counted and if the client | 69 | | // drops its reference and the IPC call is canceled, this variable keeps the | 70 | | // instance alive until the method finishes executing. The self variable | 71 | | // needs to be destroyed on the event loop thread so it is freed in a sync() | 72 | | // call below. | 73 | 6 | auto self = server.thisCap(); | 74 | 6 | auto invoke = [self = kj::mv(self), call_context = kj::mv(server_context.call_context), &server, &loop, req, fn, args...](CancelMonitor& cancel_monitor) mutable { | 75 | 6 | MP_LOG(loop, Log::Debug) << "IPC server executing request #" << req; | 76 | 6 | if (loop.testing_hook_async_request_start) loop.testing_hook_async_request_start(); | 77 | 6 | KJ_DEFER(if (loop.testing_hook_async_request_done) loop.testing_hook_async_request_done()); | 78 | 6 | ServerContext server_context{server, call_context, req}; | 79 | | // Before invoking the function, store a reference to the | 80 | | // callbackThread provided by the client in the | 81 | | // thread_local.request_threads map. This way, if this | 82 | | // server thread needs to execute any RPCs that call back to | 83 | | // the client, they will happen on the same client thread | 84 | | // that is waiting for this function, just like what would | 85 | | // happen if this were a normal function call made on the | 86 | | // local stack. | 87 | | // | 88 | | // If the request_threads map already has an entry for this | 89 | | // connection, it will be left unchanged, and it indicates | 90 | | // that the current thread is an RPC client thread which is | 91 | | // in the middle of an RPC call, and the current RPC call is | 92 | | // a nested call from the remote thread handling that RPC | 93 | | // call. In this case, the callbackThread value should point | 94 | | // to the same thread already in the map, so there is no | 95 | | // need to update the map. | 96 | 6 | auto& thread_context = g_thread_context; | 97 | 6 | auto& request_threads = thread_context.request_threads; | 98 | 6 | ConnThread request_thread; | 99 | 6 | bool inserted{false}; | 100 | 6 | Mutex cancel_mutex; | 101 | 6 | Lock cancel_lock{cancel_mutex}; | 102 | 6 | server_context.cancel_lock = &cancel_lock; | 103 | 6 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 6 | if (cancel_monitor.m_canceled) { | 106 | 6 | server_context.request_canceled = true; | 107 | 6 | return; | 108 | 6 | } | 109 | | // Detect request being canceled while it executes. | 110 | 6 | assert(!cancel_monitor.m_on_cancel); | 111 | 6 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 6 | Lock cancel_lock{cancel_mutex}; | 125 | 6 | server_context.request_canceled = true; | 126 | 6 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 6 | std::tie(request_thread, inserted) = SetThread( | 132 | 6 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 6 | }); | 135 | | | 136 | | // If an entry was inserted into the request_threads map, | 137 | | // remove it after calling fn.invoke. If an entry was not | 138 | | // inserted, one already existed, meaning this must be a | 139 | | // recursive call (IPC call calling back to the caller which | 140 | | // makes another IPC call), so avoid modifying the map. | 141 | 6 | const bool erase_thread{inserted}; | 142 | 6 | KJ_DEFER( | 143 | | // Release the cancel lock before calling loop->sync and | 144 | | // waiting for the event loop thread, because if a | 145 | | // cancellation happened, it needs to run the on_cancel | 146 | | // callback above. It's safe to release cancel_lock at | 147 | | // this point because the fn.invoke() call below will be | 148 | | // finished and no longer accessing the params or | 149 | | // results structs. | 150 | 6 | cancel_lock.m_lock.unlock(); | 151 | | // Erase the request_threads entry on the event loop | 152 | | // thread with loop->sync(), so if the connection is | 153 | | // broken there is not a race between this thread and | 154 | | // the disconnect handler trying to destroy the thread | 155 | | // client object. | 156 | 6 | loop.sync([&] { | 157 | | // Clear cancellation callback. At this point the | 158 | | // method invocation finished and the result is | 159 | | // either being returned, or discarded if a | 160 | | // cancellation happened. So we do not need to be | 161 | | // notified of cancellations after this point. Also | 162 | | // we do not want to be notified because | 163 | | // cancel_mutex and server_context could be out of | 164 | | // scope when it happens. | 165 | 6 | cancel_monitor.m_on_cancel = nullptr; | 166 | 6 | auto self_dispose{kj::mv(self)}; | 167 | 6 | if (erase_thread) { | 168 | | // Look up the thread again without using existing | 169 | | // iterator since entry may no longer be there after | 170 | | // a disconnect. Destroy node after releasing | 171 | | // Waiter::m_mutex, so the ProxyClient<Thread> | 172 | | // destructor is able to use EventLoop::mutex | 173 | | // without violating lock order. | 174 | 6 | ConnThreads::node_type removed; | 175 | 6 | { | 176 | 6 | Lock lock(thread_context.waiter->m_mutex); | 177 | 6 | removed = request_threads.extract(server.m_context.connection); | 178 | 6 | } | 179 | 6 | } | 180 | 6 | }); | 181 | 6 | ); | 182 | 6 | if (server_context.request_canceled) { | 183 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled before it could be executed"; | 184 | 6 | } else KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]{ | 185 | 6 | try { | 186 | 6 | fn.invoke(server_context, args...); | 187 | 6 | } catch (const InterruptException& e) { | 188 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " interrupted (" << e.what() << ")"; | 189 | 6 | } | 190 | 6 | })) { | 191 | 6 | MP_LOG(loop, Log::Error) << "IPC server request #" << req << " uncaught exception (" << kj::str(*exception).cStr() << ")"; | 192 | 6 | kj::throwRecoverableException(kj::mv(*exception)); | 193 | 6 | } | 194 | 6 | return call_context; | 195 | | // End of scope: if KJ_DEFER was reached, it runs here | 196 | 6 | }; | 197 | | | 198 | | // Lookup Thread object specified by the client. The specified thread should | 199 | | // be a local Thread::Server object, but it needs to be looked up | 200 | | // asynchronously with getLocalServer(). | 201 | 6 | const auto& params = server_context.call_context.getParams(); | 202 | 6 | Context::Reader context_arg = Accessor::get(params); | 203 | 6 | auto thread_client = context_arg.getThread(); | 204 | 6 | auto result = server.m_context.connection->m_threads.getLocalServer(thread_client) | 205 | 6 | .then([&loop, invoke = kj::mv(invoke), req](const kj::Maybe<Thread::Server&>& perhaps) mutable { | 206 | | // Assuming the thread object is found, pass it a pointer to the | 207 | | // `invoke` lambda above which will invoke the function on that | 208 | | // thread. | 209 | 6 | KJ_IF_MAYBE (thread_server, perhaps) { | 210 | 6 | auto& thread = static_cast<ProxyServer<Thread>&>(*thread_server); | 211 | 6 | MP_LOG(loop, Log::Debug) | 212 | 6 | << "IPC server post request #" << req << " {" << thread.m_thread_context.thread_name << "}"; | 213 | 6 | return thread.template post<typename ServerContext::CallContext>(std::move(invoke)); | 214 | 6 | } else { | 215 | 6 | MP_LOG(loop, Log::Error) | 216 | 6 | << "IPC server error request #" << req << ", missing thread to execute request"; | 217 | 6 | throw std::runtime_error("invalid thread handle"); | 218 | 6 | } | 219 | 6 | }); | 220 | | // Use connection m_canceler object to cancel the result promise if the | 221 | | // connection is destroyed. (By default Cap'n Proto does not cancel requests | 222 | | // on disconnect, since it's possible clients might want to make requests | 223 | | // and immediately disconnect without waiting for results, but not want the | 224 | | // requests to be canceled.) | 225 | 6 | return server.m_context.connection->m_canceler.wrap(kj::mv(result)); | 226 | 6 | } |
Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeMiningParams, ipc::capnp::messages::Init::MakeMiningResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&) std::enable_if<std::is_same<decltype(mp::Accessor<mp::init_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::init_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Init>, capnp::CallContext<ipc::capnp::messages::Init::MakeRpcParams, ipc::capnp::messages::Init::MakeRpcResults>>&, mp::ServerRet<mp::Accessor<mp::init_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&) Line | Count | Source | 63 | 4 | { | 64 | 4 | auto& server = server_context.proxy_server; | 65 | 4 | EventLoop& loop = *server.m_context.loop; | 66 | 4 | int req = server_context.req; | 67 | | // Keep a reference to the ProxyServer instance by assigning it to the self | 68 | | // variable. ProxyServer instances are reference-counted and if the client | 69 | | // drops its reference and the IPC call is canceled, this variable keeps the | 70 | | // instance alive until the method finishes executing. The self variable | 71 | | // needs to be destroyed on the event loop thread so it is freed in a sync() | 72 | | // call below. | 73 | 4 | auto self = server.thisCap(); | 74 | 4 | auto invoke = [self = kj::mv(self), call_context = kj::mv(server_context.call_context), &server, &loop, req, fn, args...](CancelMonitor& cancel_monitor) mutable { | 75 | 4 | MP_LOG(loop, Log::Debug) << "IPC server executing request #" << req; | 76 | 4 | if (loop.testing_hook_async_request_start) loop.testing_hook_async_request_start(); | 77 | 4 | KJ_DEFER(if (loop.testing_hook_async_request_done) loop.testing_hook_async_request_done()); | 78 | 4 | ServerContext server_context{server, call_context, req}; | 79 | | // Before invoking the function, store a reference to the | 80 | | // callbackThread provided by the client in the | 81 | | // thread_local.request_threads map. This way, if this | 82 | | // server thread needs to execute any RPCs that call back to | 83 | | // the client, they will happen on the same client thread | 84 | | // that is waiting for this function, just like what would | 85 | | // happen if this were a normal function call made on the | 86 | | // local stack. | 87 | | // | 88 | | // If the request_threads map already has an entry for this | 89 | | // connection, it will be left unchanged, and it indicates | 90 | | // that the current thread is an RPC client thread which is | 91 | | // in the middle of an RPC call, and the current RPC call is | 92 | | // a nested call from the remote thread handling that RPC | 93 | | // call. In this case, the callbackThread value should point | 94 | | // to the same thread already in the map, so there is no | 95 | | // need to update the map. | 96 | 4 | auto& thread_context = g_thread_context; | 97 | 4 | auto& request_threads = thread_context.request_threads; | 98 | 4 | ConnThread request_thread; | 99 | 4 | bool inserted{false}; | 100 | 4 | Mutex cancel_mutex; | 101 | 4 | Lock cancel_lock{cancel_mutex}; | 102 | 4 | server_context.cancel_lock = &cancel_lock; | 103 | 4 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 4 | if (cancel_monitor.m_canceled) { | 106 | 4 | server_context.request_canceled = true; | 107 | 4 | return; | 108 | 4 | } | 109 | | // Detect request being canceled while it executes. | 110 | 4 | assert(!cancel_monitor.m_on_cancel); | 111 | 4 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 4 | Lock cancel_lock{cancel_mutex}; | 125 | 4 | server_context.request_canceled = true; | 126 | 4 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 4 | std::tie(request_thread, inserted) = SetThread( | 132 | 4 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 4 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 4 | }); | 135 | | | 136 | | // If an entry was inserted into the request_threads map, | 137 | | // remove it after calling fn.invoke. If an entry was not | 138 | | // inserted, one already existed, meaning this must be a | 139 | | // recursive call (IPC call calling back to the caller which | 140 | | // makes another IPC call), so avoid modifying the map. | 141 | 4 | const bool erase_thread{inserted}; | 142 | 4 | KJ_DEFER( | 143 | | // Release the cancel lock before calling loop->sync and | 144 | | // waiting for the event loop thread, because if a | 145 | | // cancellation happened, it needs to run the on_cancel | 146 | | // callback above. It's safe to release cancel_lock at | 147 | | // this point because the fn.invoke() call below will be | 148 | | // finished and no longer accessing the params or | 149 | | // results structs. | 150 | 4 | cancel_lock.m_lock.unlock(); | 151 | | // Erase the request_threads entry on the event loop | 152 | | // thread with loop->sync(), so if the connection is | 153 | | // broken there is not a race between this thread and | 154 | | // the disconnect handler trying to destroy the thread | 155 | | // client object. | 156 | 4 | loop.sync([&] { | 157 | | // Clear cancellation callback. At this point the | 158 | | // method invocation finished and the result is | 159 | | // either being returned, or discarded if a | 160 | | // cancellation happened. So we do not need to be | 161 | | // notified of cancellations after this point. Also | 162 | | // we do not want to be notified because | 163 | | // cancel_mutex and server_context could be out of | 164 | | // scope when it happens. | 165 | 4 | cancel_monitor.m_on_cancel = nullptr; | 166 | 4 | auto self_dispose{kj::mv(self)}; | 167 | 4 | if (erase_thread) { | 168 | | // Look up the thread again without using existing | 169 | | // iterator since entry may no longer be there after | 170 | | // a disconnect. Destroy node after releasing | 171 | | // Waiter::m_mutex, so the ProxyClient<Thread> | 172 | | // destructor is able to use EventLoop::mutex | 173 | | // without violating lock order. | 174 | 4 | ConnThreads::node_type removed; | 175 | 4 | { | 176 | 4 | Lock lock(thread_context.waiter->m_mutex); | 177 | 4 | removed = request_threads.extract(server.m_context.connection); | 178 | 4 | } | 179 | 4 | } | 180 | 4 | }); | 181 | 4 | ); | 182 | 4 | if (server_context.request_canceled) { | 183 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled before it could be executed"; | 184 | 4 | } else KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]{ | 185 | 4 | try { | 186 | 4 | fn.invoke(server_context, args...); | 187 | 4 | } catch (const InterruptException& e) { | 188 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " interrupted (" << e.what() << ")"; | 189 | 4 | } | 190 | 4 | })) { | 191 | 4 | MP_LOG(loop, Log::Error) << "IPC server request #" << req << " uncaught exception (" << kj::str(*exception).cStr() << ")"; | 192 | 4 | kj::throwRecoverableException(kj::mv(*exception)); | 193 | 4 | } | 194 | 4 | return call_context; | 195 | | // End of scope: if KJ_DEFER was reached, it runs here | 196 | 4 | }; | 197 | | | 198 | | // Lookup Thread object specified by the client. The specified thread should | 199 | | // be a local Thread::Server object, but it needs to be looked up | 200 | | // asynchronously with getLocalServer(). | 201 | 4 | const auto& params = server_context.call_context.getParams(); | 202 | 4 | Context::Reader context_arg = Accessor::get(params); | 203 | 4 | auto thread_client = context_arg.getThread(); | 204 | 4 | auto result = server.m_context.connection->m_threads.getLocalServer(thread_client) | 205 | 4 | .then([&loop, invoke = kj::mv(invoke), req](const kj::Maybe<Thread::Server&>& perhaps) mutable { | 206 | | // Assuming the thread object is found, pass it a pointer to the | 207 | | // `invoke` lambda above which will invoke the function on that | 208 | | // thread. | 209 | 4 | KJ_IF_MAYBE (thread_server, perhaps) { | 210 | 4 | auto& thread = static_cast<ProxyServer<Thread>&>(*thread_server); | 211 | 4 | MP_LOG(loop, Log::Debug) | 212 | 4 | << "IPC server post request #" << req << " {" << thread.m_thread_context.thread_name << "}"; | 213 | 4 | return thread.template post<typename ServerContext::CallContext>(std::move(invoke)); | 214 | 4 | } else { | 215 | 4 | MP_LOG(loop, Log::Error) | 216 | 4 | << "IPC server error request #" << req << ", missing thread to execute request"; | 217 | 4 | throw std::runtime_error("invalid thread handle"); | 218 | 4 | } | 219 | 4 | }); | 220 | | // Use connection m_canceler object to cancel the result promise if the | 221 | | // connection is destroyed. (By default Cap'n Proto does not cancel requests | 222 | | // on disconnect, since it's possible clients might want to make requests | 223 | | // and immediately disconnect without waiting for results, but not want the | 224 | | // requests to be canceled.) | 225 | 4 | return server.m_context.connection->m_canceler.wrap(kj::mv(result)); | 226 | 4 | } |
Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsTestChainParams, ipc::capnp::messages::Mining::IsTestChainResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::IsInitialBlockDownloadParams, ipc::capnp::messages::Mining::IsInitialBlockDownloadResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall> const&, mp::TypeList<>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::GetTipParams, ipc::capnp::messages::Mining::GetTipResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 22>, mp::ServerCall> const&, mp::TypeList<>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::WaitTipChangedParams, ipc::capnp::messages::Mining::WaitTipChangedResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::CurrentTip, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timeout, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<uint256, std::chrono::duration<double, std::ratio<1l, 1000l>>>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>>, mp::TypeList<node::BlockCreateOptions const&, bool>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CreateNewBlockParams, ipc::capnp::messages::Mining::CreateNewBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Cooldown, 1>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>> const&, mp::TypeList<node::BlockCreateOptions const&, bool>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Mining>, capnp::CallContext<ipc::capnp::messages::Mining::CheckBlockParams, ipc::capnp::messages::Mining::CheckBlockResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Block, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Reason, 18>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Debug, 18>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<CBlock const&, node::BlockCheckOptions const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>&>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::DestroyParams, ipc::capnp::messages::BlockTemplate::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockHeaderParams, ipc::capnp::messages::BlockTemplate::GetBlockHeaderResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetBlockParams, ipc::capnp::messages::BlockTemplate::GetBlockResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxFeesParams, ipc::capnp::messages::BlockTemplate::GetTxFeesResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetTxSigopsParams, ipc::capnp::messages::BlockTemplate::GetTxSigopsResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseTxParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseTxResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathParams, ipc::capnp::messages::BlockTemplate::GetCoinbaseMerklePathResults>>&, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall> const&, mp::TypeList<>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>>, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::SubmitSolutionParams, ipc::capnp::messages::BlockTemplate::SubmitSolutionResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Version, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Timestamp, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Nonce, 1>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Coinbase, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 2>, mp::ServerCall>>>>> const&, mp::TypeList<unsigned int, unsigned int, unsigned int, std::shared_ptr<CTransaction const>>&&) Unexecuted instantiation: std::enable_if<std::is_same<decltype(mp::Accessor<mp::mining_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::mining_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<node::BlockWaitOptions>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::BlockTemplate>, capnp::CallContext<ipc::capnp::messages::BlockTemplate::WaitNextParams, ipc::capnp::messages::BlockTemplate::WaitNextResults>>&, mp::ServerField<1, mp::Accessor<mp::mining_fields::Options, 17>, mp::ServerRet<mp::Accessor<mp::mining_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<node::BlockWaitOptions>&&) std::enable_if<std::is_same<decltype(mp::Accessor<mp::rpc_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::rpc_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>>, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Rpc>, capnp::CallContext<ipc::capnp::messages::Rpc::ExecuteRpcParams, ipc::capnp::messages::Rpc::ExecuteRpcResults>>&, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Request, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::Uri, 17>, mp::ServerField<1, mp::Accessor<mp::rpc_fields::User, 17>, mp::ServerRet<mp::Accessor<mp::rpc_fields::Result, 18>, mp::ServerCall>>>> const&, mp::TypeList<UniValue, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>>&&) Line | Count | Source | 63 | 4 | { | 64 | 4 | auto& server = server_context.proxy_server; | 65 | 4 | EventLoop& loop = *server.m_context.loop; | 66 | 4 | int req = server_context.req; | 67 | | // Keep a reference to the ProxyServer instance by assigning it to the self | 68 | | // variable. ProxyServer instances are reference-counted and if the client | 69 | | // drops its reference and the IPC call is canceled, this variable keeps the | 70 | | // instance alive until the method finishes executing. The self variable | 71 | | // needs to be destroyed on the event loop thread so it is freed in a sync() | 72 | | // call below. | 73 | 4 | auto self = server.thisCap(); | 74 | 4 | auto invoke = [self = kj::mv(self), call_context = kj::mv(server_context.call_context), &server, &loop, req, fn, args...](CancelMonitor& cancel_monitor) mutable { | 75 | 4 | MP_LOG(loop, Log::Debug) << "IPC server executing request #" << req; | 76 | 4 | if (loop.testing_hook_async_request_start) loop.testing_hook_async_request_start(); | 77 | 4 | KJ_DEFER(if (loop.testing_hook_async_request_done) loop.testing_hook_async_request_done()); | 78 | 4 | ServerContext server_context{server, call_context, req}; | 79 | | // Before invoking the function, store a reference to the | 80 | | // callbackThread provided by the client in the | 81 | | // thread_local.request_threads map. This way, if this | 82 | | // server thread needs to execute any RPCs that call back to | 83 | | // the client, they will happen on the same client thread | 84 | | // that is waiting for this function, just like what would | 85 | | // happen if this were a normal function call made on the | 86 | | // local stack. | 87 | | // | 88 | | // If the request_threads map already has an entry for this | 89 | | // connection, it will be left unchanged, and it indicates | 90 | | // that the current thread is an RPC client thread which is | 91 | | // in the middle of an RPC call, and the current RPC call is | 92 | | // a nested call from the remote thread handling that RPC | 93 | | // call. In this case, the callbackThread value should point | 94 | | // to the same thread already in the map, so there is no | 95 | | // need to update the map. | 96 | 4 | auto& thread_context = g_thread_context; | 97 | 4 | auto& request_threads = thread_context.request_threads; | 98 | 4 | ConnThread request_thread; | 99 | 4 | bool inserted{false}; | 100 | 4 | Mutex cancel_mutex; | 101 | 4 | Lock cancel_lock{cancel_mutex}; | 102 | 4 | server_context.cancel_lock = &cancel_lock; | 103 | 4 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 4 | if (cancel_monitor.m_canceled) { | 106 | 4 | server_context.request_canceled = true; | 107 | 4 | return; | 108 | 4 | } | 109 | | // Detect request being canceled while it executes. | 110 | 4 | assert(!cancel_monitor.m_on_cancel); | 111 | 4 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 4 | Lock cancel_lock{cancel_mutex}; | 125 | 4 | server_context.request_canceled = true; | 126 | 4 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 4 | std::tie(request_thread, inserted) = SetThread( | 132 | 4 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 4 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 4 | }); | 135 | | | 136 | | // If an entry was inserted into the request_threads map, | 137 | | // remove it after calling fn.invoke. If an entry was not | 138 | | // inserted, one already existed, meaning this must be a | 139 | | // recursive call (IPC call calling back to the caller which | 140 | | // makes another IPC call), so avoid modifying the map. | 141 | 4 | const bool erase_thread{inserted}; | 142 | 4 | KJ_DEFER( | 143 | | // Release the cancel lock before calling loop->sync and | 144 | | // waiting for the event loop thread, because if a | 145 | | // cancellation happened, it needs to run the on_cancel | 146 | | // callback above. It's safe to release cancel_lock at | 147 | | // this point because the fn.invoke() call below will be | 148 | | // finished and no longer accessing the params or | 149 | | // results structs. | 150 | 4 | cancel_lock.m_lock.unlock(); | 151 | | // Erase the request_threads entry on the event loop | 152 | | // thread with loop->sync(), so if the connection is | 153 | | // broken there is not a race between this thread and | 154 | | // the disconnect handler trying to destroy the thread | 155 | | // client object. | 156 | 4 | loop.sync([&] { | 157 | | // Clear cancellation callback. At this point the | 158 | | // method invocation finished and the result is | 159 | | // either being returned, or discarded if a | 160 | | // cancellation happened. So we do not need to be | 161 | | // notified of cancellations after this point. Also | 162 | | // we do not want to be notified because | 163 | | // cancel_mutex and server_context could be out of | 164 | | // scope when it happens. | 165 | 4 | cancel_monitor.m_on_cancel = nullptr; | 166 | 4 | auto self_dispose{kj::mv(self)}; | 167 | 4 | if (erase_thread) { | 168 | | // Look up the thread again without using existing | 169 | | // iterator since entry may no longer be there after | 170 | | // a disconnect. Destroy node after releasing | 171 | | // Waiter::m_mutex, so the ProxyClient<Thread> | 172 | | // destructor is able to use EventLoop::mutex | 173 | | // without violating lock order. | 174 | 4 | ConnThreads::node_type removed; | 175 | 4 | { | 176 | 4 | Lock lock(thread_context.waiter->m_mutex); | 177 | 4 | removed = request_threads.extract(server.m_context.connection); | 178 | 4 | } | 179 | 4 | } | 180 | 4 | }); | 181 | 4 | ); | 182 | 4 | if (server_context.request_canceled) { | 183 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled before it could be executed"; | 184 | 4 | } else KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]{ | 185 | 4 | try { | 186 | 4 | fn.invoke(server_context, args...); | 187 | 4 | } catch (const InterruptException& e) { | 188 | 4 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " interrupted (" << e.what() << ")"; | 189 | 4 | } | 190 | 4 | })) { | 191 | 4 | MP_LOG(loop, Log::Error) << "IPC server request #" << req << " uncaught exception (" << kj::str(*exception).cStr() << ")"; | 192 | 4 | kj::throwRecoverableException(kj::mv(*exception)); | 193 | 4 | } | 194 | 4 | return call_context; | 195 | | // End of scope: if KJ_DEFER was reached, it runs here | 196 | 4 | }; | 197 | | | 198 | | // Lookup Thread object specified by the client. The specified thread should | 199 | | // be a local Thread::Server object, but it needs to be looked up | 200 | | // asynchronously with getLocalServer(). | 201 | 4 | const auto& params = server_context.call_context.getParams(); | 202 | 4 | Context::Reader context_arg = Accessor::get(params); | 203 | 4 | auto thread_client = context_arg.getThread(); | 204 | 4 | auto result = server.m_context.connection->m_threads.getLocalServer(thread_client) | 205 | 4 | .then([&loop, invoke = kj::mv(invoke), req](const kj::Maybe<Thread::Server&>& perhaps) mutable { | 206 | | // Assuming the thread object is found, pass it a pointer to the | 207 | | // `invoke` lambda above which will invoke the function on that | 208 | | // thread. | 209 | 4 | KJ_IF_MAYBE (thread_server, perhaps) { | 210 | 4 | auto& thread = static_cast<ProxyServer<Thread>&>(*thread_server); | 211 | 4 | MP_LOG(loop, Log::Debug) | 212 | 4 | << "IPC server post request #" << req << " {" << thread.m_thread_context.thread_name << "}"; | 213 | 4 | return thread.template post<typename ServerContext::CallContext>(std::move(invoke)); | 214 | 4 | } else { | 215 | 4 | MP_LOG(loop, Log::Error) | 216 | 4 | << "IPC server error request #" << req << ", missing thread to execute request"; | 217 | 4 | throw std::runtime_error("invalid thread handle"); | 218 | 4 | } | 219 | 4 | }); | 220 | | // Use connection m_canceler object to cancel the result promise if the | 221 | | // connection is destroyed. (By default Cap'n Proto does not cancel requests | 222 | | // on disconnect, since it's possible clients might want to make requests | 223 | | // and immediately disconnect without waiting for results, but not want the | 224 | | // requests to be canceled.) | 225 | 4 | return server.m_context.connection->m_canceler.wrap(kj::mv(result)); | 226 | 4 | } |
std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>, mp::ServerDestroy, mp::TypeList<>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::DestroyParams, ipc::capnp::messages::Echo::DestroyResults>>&, mp::ServerDestroy const&, mp::TypeList<>&&) Line | Count | Source | 63 | 6 | { | 64 | 6 | auto& server = server_context.proxy_server; | 65 | 6 | EventLoop& loop = *server.m_context.loop; | 66 | 6 | int req = server_context.req; | 67 | | // Keep a reference to the ProxyServer instance by assigning it to the self | 68 | | // variable. ProxyServer instances are reference-counted and if the client | 69 | | // drops its reference and the IPC call is canceled, this variable keeps the | 70 | | // instance alive until the method finishes executing. The self variable | 71 | | // needs to be destroyed on the event loop thread so it is freed in a sync() | 72 | | // call below. | 73 | 6 | auto self = server.thisCap(); | 74 | 6 | auto invoke = [self = kj::mv(self), call_context = kj::mv(server_context.call_context), &server, &loop, req, fn, args...](CancelMonitor& cancel_monitor) mutable { | 75 | 6 | MP_LOG(loop, Log::Debug) << "IPC server executing request #" << req; | 76 | 6 | if (loop.testing_hook_async_request_start) loop.testing_hook_async_request_start(); | 77 | 6 | KJ_DEFER(if (loop.testing_hook_async_request_done) loop.testing_hook_async_request_done()); | 78 | 6 | ServerContext server_context{server, call_context, req}; | 79 | | // Before invoking the function, store a reference to the | 80 | | // callbackThread provided by the client in the | 81 | | // thread_local.request_threads map. This way, if this | 82 | | // server thread needs to execute any RPCs that call back to | 83 | | // the client, they will happen on the same client thread | 84 | | // that is waiting for this function, just like what would | 85 | | // happen if this were a normal function call made on the | 86 | | // local stack. | 87 | | // | 88 | | // If the request_threads map already has an entry for this | 89 | | // connection, it will be left unchanged, and it indicates | 90 | | // that the current thread is an RPC client thread which is | 91 | | // in the middle of an RPC call, and the current RPC call is | 92 | | // a nested call from the remote thread handling that RPC | 93 | | // call. In this case, the callbackThread value should point | 94 | | // to the same thread already in the map, so there is no | 95 | | // need to update the map. | 96 | 6 | auto& thread_context = g_thread_context; | 97 | 6 | auto& request_threads = thread_context.request_threads; | 98 | 6 | ConnThread request_thread; | 99 | 6 | bool inserted{false}; | 100 | 6 | Mutex cancel_mutex; | 101 | 6 | Lock cancel_lock{cancel_mutex}; | 102 | 6 | server_context.cancel_lock = &cancel_lock; | 103 | 6 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 6 | if (cancel_monitor.m_canceled) { | 106 | 6 | server_context.request_canceled = true; | 107 | 6 | return; | 108 | 6 | } | 109 | | // Detect request being canceled while it executes. | 110 | 6 | assert(!cancel_monitor.m_on_cancel); | 111 | 6 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 6 | Lock cancel_lock{cancel_mutex}; | 125 | 6 | server_context.request_canceled = true; | 126 | 6 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 6 | std::tie(request_thread, inserted) = SetThread( | 132 | 6 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 6 | }); | 135 | | | 136 | | // If an entry was inserted into the request_threads map, | 137 | | // remove it after calling fn.invoke. If an entry was not | 138 | | // inserted, one already existed, meaning this must be a | 139 | | // recursive call (IPC call calling back to the caller which | 140 | | // makes another IPC call), so avoid modifying the map. | 141 | 6 | const bool erase_thread{inserted}; | 142 | 6 | KJ_DEFER( | 143 | | // Release the cancel lock before calling loop->sync and | 144 | | // waiting for the event loop thread, because if a | 145 | | // cancellation happened, it needs to run the on_cancel | 146 | | // callback above. It's safe to release cancel_lock at | 147 | | // this point because the fn.invoke() call below will be | 148 | | // finished and no longer accessing the params or | 149 | | // results structs. | 150 | 6 | cancel_lock.m_lock.unlock(); | 151 | | // Erase the request_threads entry on the event loop | 152 | | // thread with loop->sync(), so if the connection is | 153 | | // broken there is not a race between this thread and | 154 | | // the disconnect handler trying to destroy the thread | 155 | | // client object. | 156 | 6 | loop.sync([&] { | 157 | | // Clear cancellation callback. At this point the | 158 | | // method invocation finished and the result is | 159 | | // either being returned, or discarded if a | 160 | | // cancellation happened. So we do not need to be | 161 | | // notified of cancellations after this point. Also | 162 | | // we do not want to be notified because | 163 | | // cancel_mutex and server_context could be out of | 164 | | // scope when it happens. | 165 | 6 | cancel_monitor.m_on_cancel = nullptr; | 166 | 6 | auto self_dispose{kj::mv(self)}; | 167 | 6 | if (erase_thread) { | 168 | | // Look up the thread again without using existing | 169 | | // iterator since entry may no longer be there after | 170 | | // a disconnect. Destroy node after releasing | 171 | | // Waiter::m_mutex, so the ProxyClient<Thread> | 172 | | // destructor is able to use EventLoop::mutex | 173 | | // without violating lock order. | 174 | 6 | ConnThreads::node_type removed; | 175 | 6 | { | 176 | 6 | Lock lock(thread_context.waiter->m_mutex); | 177 | 6 | removed = request_threads.extract(server.m_context.connection); | 178 | 6 | } | 179 | 6 | } | 180 | 6 | }); | 181 | 6 | ); | 182 | 6 | if (server_context.request_canceled) { | 183 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled before it could be executed"; | 184 | 6 | } else KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]{ | 185 | 6 | try { | 186 | 6 | fn.invoke(server_context, args...); | 187 | 6 | } catch (const InterruptException& e) { | 188 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " interrupted (" << e.what() << ")"; | 189 | 6 | } | 190 | 6 | })) { | 191 | 6 | MP_LOG(loop, Log::Error) << "IPC server request #" << req << " uncaught exception (" << kj::str(*exception).cStr() << ")"; | 192 | 6 | kj::throwRecoverableException(kj::mv(*exception)); | 193 | 6 | } | 194 | 6 | return call_context; | 195 | | // End of scope: if KJ_DEFER was reached, it runs here | 196 | 6 | }; | 197 | | | 198 | | // Lookup Thread object specified by the client. The specified thread should | 199 | | // be a local Thread::Server object, but it needs to be looked up | 200 | | // asynchronously with getLocalServer(). | 201 | 6 | const auto& params = server_context.call_context.getParams(); | 202 | 6 | Context::Reader context_arg = Accessor::get(params); | 203 | 6 | auto thread_client = context_arg.getThread(); | 204 | 6 | auto result = server.m_context.connection->m_threads.getLocalServer(thread_client) | 205 | 6 | .then([&loop, invoke = kj::mv(invoke), req](const kj::Maybe<Thread::Server&>& perhaps) mutable { | 206 | | // Assuming the thread object is found, pass it a pointer to the | 207 | | // `invoke` lambda above which will invoke the function on that | 208 | | // thread. | 209 | 6 | KJ_IF_MAYBE (thread_server, perhaps) { | 210 | 6 | auto& thread = static_cast<ProxyServer<Thread>&>(*thread_server); | 211 | 6 | MP_LOG(loop, Log::Debug) | 212 | 6 | << "IPC server post request #" << req << " {" << thread.m_thread_context.thread_name << "}"; | 213 | 6 | return thread.template post<typename ServerContext::CallContext>(std::move(invoke)); | 214 | 6 | } else { | 215 | 6 | MP_LOG(loop, Log::Error) | 216 | 6 | << "IPC server error request #" << req << ", missing thread to execute request"; | 217 | 6 | throw std::runtime_error("invalid thread handle"); | 218 | 6 | } | 219 | 6 | }); | 220 | | // Use connection m_canceler object to cancel the result promise if the | 221 | | // connection is destroyed. (By default Cap'n Proto does not cancel requests | 222 | | // on disconnect, since it's possible clients might want to make requests | 223 | | // and immediately disconnect without waiting for results, but not want the | 224 | | // requests to be canceled.) | 225 | 6 | return server.m_context.connection->m_canceler.wrap(kj::mv(result)); | 226 | 6 | } |
std::enable_if<std::is_same<decltype(mp::Accessor<mp::echo_fields::Context, 17>::get(fp1.call_context.getParams())), mp::Context::Reader>::value, kj::Promise<mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>::CallContext>>::type mp::PassField<mp::Accessor<mp::echo_fields::Context, 17>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>>, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>>(mp::Priority<1>, mp::TypeList<>, mp::ServerInvokeContext<mp::ProxyServer<ipc::capnp::messages::Echo>, capnp::CallContext<ipc::capnp::messages::Echo::EchoParams, ipc::capnp::messages::Echo::EchoResults>>&, mp::ServerField<1, mp::Accessor<mp::echo_fields::Echo, 17>, mp::ServerRet<mp::Accessor<mp::echo_fields::Result, 18>, mp::ServerCall>> const&, mp::TypeList<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> const&>&&) Line | Count | Source | 63 | 6 | { | 64 | 6 | auto& server = server_context.proxy_server; | 65 | 6 | EventLoop& loop = *server.m_context.loop; | 66 | 6 | int req = server_context.req; | 67 | | // Keep a reference to the ProxyServer instance by assigning it to the self | 68 | | // variable. ProxyServer instances are reference-counted and if the client | 69 | | // drops its reference and the IPC call is canceled, this variable keeps the | 70 | | // instance alive until the method finishes executing. The self variable | 71 | | // needs to be destroyed on the event loop thread so it is freed in a sync() | 72 | | // call below. | 73 | 6 | auto self = server.thisCap(); | 74 | 6 | auto invoke = [self = kj::mv(self), call_context = kj::mv(server_context.call_context), &server, &loop, req, fn, args...](CancelMonitor& cancel_monitor) mutable { | 75 | 6 | MP_LOG(loop, Log::Debug) << "IPC server executing request #" << req; | 76 | 6 | if (loop.testing_hook_async_request_start) loop.testing_hook_async_request_start(); | 77 | 6 | KJ_DEFER(if (loop.testing_hook_async_request_done) loop.testing_hook_async_request_done()); | 78 | 6 | ServerContext server_context{server, call_context, req}; | 79 | | // Before invoking the function, store a reference to the | 80 | | // callbackThread provided by the client in the | 81 | | // thread_local.request_threads map. This way, if this | 82 | | // server thread needs to execute any RPCs that call back to | 83 | | // the client, they will happen on the same client thread | 84 | | // that is waiting for this function, just like what would | 85 | | // happen if this were a normal function call made on the | 86 | | // local stack. | 87 | | // | 88 | | // If the request_threads map already has an entry for this | 89 | | // connection, it will be left unchanged, and it indicates | 90 | | // that the current thread is an RPC client thread which is | 91 | | // in the middle of an RPC call, and the current RPC call is | 92 | | // a nested call from the remote thread handling that RPC | 93 | | // call. In this case, the callbackThread value should point | 94 | | // to the same thread already in the map, so there is no | 95 | | // need to update the map. | 96 | 6 | auto& thread_context = g_thread_context; | 97 | 6 | auto& request_threads = thread_context.request_threads; | 98 | 6 | ConnThread request_thread; | 99 | 6 | bool inserted{false}; | 100 | 6 | Mutex cancel_mutex; | 101 | 6 | Lock cancel_lock{cancel_mutex}; | 102 | 6 | server_context.cancel_lock = &cancel_lock; | 103 | 6 | loop.sync([&] { | 104 | | // Detect request being canceled before it executes. | 105 | 6 | if (cancel_monitor.m_canceled) { | 106 | 6 | server_context.request_canceled = true; | 107 | 6 | return; | 108 | 6 | } | 109 | | // Detect request being canceled while it executes. | 110 | 6 | assert(!cancel_monitor.m_on_cancel); | 111 | 6 | cancel_monitor.m_on_cancel = [&loop, &server_context, &cancel_mutex, req]() { | 112 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled while executing."; | 113 | | // Lock cancel_mutex here to block the event loop | 114 | | // thread and prevent it from deleting the request's | 115 | | // params and response structs while the execution | 116 | | // thread is accessing them. Because this lock is | 117 | | // released before the event loop thread does delete | 118 | | // the structs, the mutex does not provide any | 119 | | // protection from the event loop deleting the | 120 | | // structs _before_ the execution thread acquires | 121 | | // it. So in addition to locking the mutex, the | 122 | | // execution thread always checks request_canceled | 123 | | // as well before accessing the structs. | 124 | 6 | Lock cancel_lock{cancel_mutex}; | 125 | 6 | server_context.request_canceled = true; | 126 | 6 | }; | 127 | | // Update requests_threads map if not canceled. We know | 128 | | // the request is not canceled currently because | 129 | | // cancel_monitor.m_canceled was checked above and this | 130 | | // code is running on the event loop thread. | 131 | 6 | std::tie(request_thread, inserted) = SetThread( | 132 | 6 | GuardedRef{thread_context.waiter->m_mutex, request_threads}, server.m_context.connection, | 133 | 6 | [&] { return Accessor::get(call_context.getParams()).getCallbackThread(); }); | 134 | 6 | }); | 135 | | | 136 | | // If an entry was inserted into the request_threads map, | 137 | | // remove it after calling fn.invoke. If an entry was not | 138 | | // inserted, one already existed, meaning this must be a | 139 | | // recursive call (IPC call calling back to the caller which | 140 | | // makes another IPC call), so avoid modifying the map. | 141 | 6 | const bool erase_thread{inserted}; | 142 | 6 | KJ_DEFER( | 143 | | // Release the cancel lock before calling loop->sync and | 144 | | // waiting for the event loop thread, because if a | 145 | | // cancellation happened, it needs to run the on_cancel | 146 | | // callback above. It's safe to release cancel_lock at | 147 | | // this point because the fn.invoke() call below will be | 148 | | // finished and no longer accessing the params or | 149 | | // results structs. | 150 | 6 | cancel_lock.m_lock.unlock(); | 151 | | // Erase the request_threads entry on the event loop | 152 | | // thread with loop->sync(), so if the connection is | 153 | | // broken there is not a race between this thread and | 154 | | // the disconnect handler trying to destroy the thread | 155 | | // client object. | 156 | 6 | loop.sync([&] { | 157 | | // Clear cancellation callback. At this point the | 158 | | // method invocation finished and the result is | 159 | | // either being returned, or discarded if a | 160 | | // cancellation happened. So we do not need to be | 161 | | // notified of cancellations after this point. Also | 162 | | // we do not want to be notified because | 163 | | // cancel_mutex and server_context could be out of | 164 | | // scope when it happens. | 165 | 6 | cancel_monitor.m_on_cancel = nullptr; | 166 | 6 | auto self_dispose{kj::mv(self)}; | 167 | 6 | if (erase_thread) { | 168 | | // Look up the thread again without using existing | 169 | | // iterator since entry may no longer be there after | 170 | | // a disconnect. Destroy node after releasing | 171 | | // Waiter::m_mutex, so the ProxyClient<Thread> | 172 | | // destructor is able to use EventLoop::mutex | 173 | | // without violating lock order. | 174 | 6 | ConnThreads::node_type removed; | 175 | 6 | { | 176 | 6 | Lock lock(thread_context.waiter->m_mutex); | 177 | 6 | removed = request_threads.extract(server.m_context.connection); | 178 | 6 | } | 179 | 6 | } | 180 | 6 | }); | 181 | 6 | ); | 182 | 6 | if (server_context.request_canceled) { | 183 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " canceled before it could be executed"; | 184 | 6 | } else KJ_IF_MAYBE(exception, kj::runCatchingExceptions([&]{ | 185 | 6 | try { | 186 | 6 | fn.invoke(server_context, args...); | 187 | 6 | } catch (const InterruptException& e) { | 188 | 6 | MP_LOG(loop, Log::Info) << "IPC server request #" << req << " interrupted (" << e.what() << ")"; | 189 | 6 | } | 190 | 6 | })) { | 191 | 6 | MP_LOG(loop, Log::Error) << "IPC server request #" << req << " uncaught exception (" << kj::str(*exception).cStr() << ")"; | 192 | 6 | kj::throwRecoverableException(kj::mv(*exception)); | 193 | 6 | } | 194 | 6 | return call_context; | 195 | | // End of scope: if KJ_DEFER was reached, it runs here | 196 | 6 | }; | 197 | | | 198 | | // Lookup Thread object specified by the client. The specified thread should | 199 | | // be a local Thread::Server object, but it needs to be looked up | 200 | | // asynchronously with getLocalServer(). | 201 | 6 | const auto& params = server_context.call_context.getParams(); | 202 | 6 | Context::Reader context_arg = Accessor::get(params); | 203 | 6 | auto thread_client = context_arg.getThread(); | 204 | 6 | auto result = server.m_context.connection->m_threads.getLocalServer(thread_client) | 205 | 6 | .then([&loop, invoke = kj::mv(invoke), req](const kj::Maybe<Thread::Server&>& perhaps) mutable { | 206 | | // Assuming the thread object is found, pass it a pointer to the | 207 | | // `invoke` lambda above which will invoke the function on that | 208 | | // thread. | 209 | 6 | KJ_IF_MAYBE (thread_server, perhaps) { | 210 | 6 | auto& thread = static_cast<ProxyServer<Thread>&>(*thread_server); | 211 | 6 | MP_LOG(loop, Log::Debug) | 212 | 6 | << "IPC server post request #" << req << " {" << thread.m_thread_context.thread_name << "}"; | 213 | 6 | return thread.template post<typename ServerContext::CallContext>(std::move(invoke)); | 214 | 6 | } else { | 215 | 6 | MP_LOG(loop, Log::Error) | 216 | 6 | << "IPC server error request #" << req << ", missing thread to execute request"; | 217 | 6 | throw std::runtime_error("invalid thread handle"); | 218 | 6 | } | 219 | 6 | }); | 220 | | // Use connection m_canceler object to cancel the result promise if the | 221 | | // connection is destroyed. (By default Cap'n Proto does not cancel requests | 222 | | // on disconnect, since it's possible clients might want to make requests | 223 | | // and immediately disconnect without waiting for results, but not want the | 224 | | // requests to be canceled.) | 225 | 6 | return server.m_context.connection->m_canceler.wrap(kj::mv(result)); | 226 | 6 | } |
|
227 | | } // namespace mp |
228 | | |
229 | | #endif // MP_PROXY_TYPE_CONTEXT_H |