Coverage Report

Created: 2026-05-06 07:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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