diff options
Diffstat (limited to 'src/ipc/capnp')
-rw-r--r-- | src/ipc/capnp/.gitignore | 2 | ||||
-rw-r--r-- | src/ipc/capnp/context.h | 23 | ||||
-rw-r--r-- | src/ipc/capnp/echo.capnp | 17 | ||||
-rw-r--r-- | src/ipc/capnp/init-types.h | 10 | ||||
-rw-r--r-- | src/ipc/capnp/init.capnp | 20 | ||||
-rw-r--r-- | src/ipc/capnp/protocol.cpp | 93 | ||||
-rw-r--r-- | src/ipc/capnp/protocol.h | 17 |
7 files changed, 182 insertions, 0 deletions
diff --git a/src/ipc/capnp/.gitignore b/src/ipc/capnp/.gitignore new file mode 100644 index 0000000000..036df1430c --- /dev/null +++ b/src/ipc/capnp/.gitignore @@ -0,0 +1,2 @@ +# capnp generated files +*.capnp.* diff --git a/src/ipc/capnp/context.h b/src/ipc/capnp/context.h new file mode 100644 index 0000000000..06e1614494 --- /dev/null +++ b/src/ipc/capnp/context.h @@ -0,0 +1,23 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_IPC_CAPNP_CONTEXT_H +#define BITCOIN_IPC_CAPNP_CONTEXT_H + +#include <ipc/context.h> + +namespace ipc { +namespace capnp { +//! Cap'n Proto context struct. Generally the parent ipc::Context struct should +//! be used instead of this struct to give all IPC protocols access to +//! application state, so there aren't unnecessary differences between IPC +//! protocols. But this specialized struct can be used to pass capnp-specific +//! function and object types to capnp hooks. +struct Context : ipc::Context +{ +}; +} // namespace capnp +} // namespace ipc + +#endif // BITCOIN_IPC_CAPNP_CONTEXT_H diff --git a/src/ipc/capnp/echo.capnp b/src/ipc/capnp/echo.capnp new file mode 100644 index 0000000000..df36ee0de3 --- /dev/null +++ b/src/ipc/capnp/echo.capnp @@ -0,0 +1,17 @@ +# Copyright (c) 2021 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +@0x888b4f7f51e691f7; + +using Cxx = import "/capnp/c++.capnp"; +$Cxx.namespace("ipc::capnp::messages"); + +using Proxy = import "/mp/proxy.capnp"; +$Proxy.include("interfaces/echo.h"); +$Proxy.include("ipc/capnp/echo.capnp.h"); + +interface Echo $Proxy.wrap("interfaces::Echo") { + destroy @0 (context :Proxy.Context) -> (); + echo @1 (context :Proxy.Context, echo: Text) -> (result :Text); +} diff --git a/src/ipc/capnp/init-types.h b/src/ipc/capnp/init-types.h new file mode 100644 index 0000000000..42031441b5 --- /dev/null +++ b/src/ipc/capnp/init-types.h @@ -0,0 +1,10 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_IPC_CAPNP_INIT_TYPES_H +#define BITCOIN_IPC_CAPNP_INIT_TYPES_H + +#include <ipc/capnp/echo.capnp.proxy-types.h> + +#endif // BITCOIN_IPC_CAPNP_INIT_TYPES_H diff --git a/src/ipc/capnp/init.capnp b/src/ipc/capnp/init.capnp new file mode 100644 index 0000000000..e6d358c665 --- /dev/null +++ b/src/ipc/capnp/init.capnp @@ -0,0 +1,20 @@ +# Copyright (c) 2021 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +@0xf2c5cfa319406aa6; + +using Cxx = import "/capnp/c++.capnp"; +$Cxx.namespace("ipc::capnp::messages"); + +using Proxy = import "/mp/proxy.capnp"; +$Proxy.include("interfaces/echo.h"); +$Proxy.include("interfaces/init.h"); +$Proxy.includeTypes("ipc/capnp/init-types.h"); + +using Echo = import "echo.capnp"; + +interface Init $Proxy.wrap("interfaces::Init") { + construct @0 (threadMap: Proxy.ThreadMap) -> (threadMap :Proxy.ThreadMap); + makeEcho @1 (context :Proxy.Context) -> (result :Echo.Echo); +} diff --git a/src/ipc/capnp/protocol.cpp b/src/ipc/capnp/protocol.cpp new file mode 100644 index 0000000000..37b57a9525 --- /dev/null +++ b/src/ipc/capnp/protocol.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <interfaces/init.h> +#include <ipc/capnp/context.h> +#include <ipc/capnp/init.capnp.h> +#include <ipc/capnp/init.capnp.proxy.h> +#include <ipc/capnp/protocol.h> +#include <ipc/exception.h> +#include <ipc/protocol.h> +#include <kj/async.h> +#include <logging.h> +#include <mp/proxy-io.h> +#include <mp/proxy-types.h> +#include <mp/util.h> +#include <util/threadnames.h> + +#include <assert.h> +#include <errno.h> +#include <future> +#include <memory> +#include <mutex> +#include <optional> +#include <string> +#include <thread> + +namespace ipc { +namespace capnp { +namespace { +void IpcLogFn(bool raise, std::string message) +{ + LogPrint(BCLog::IPC, "%s\n", message); + if (raise) throw Exception(message); +} + +class CapnpProtocol : public Protocol +{ +public: + ~CapnpProtocol() noexcept(true) + { + if (m_loop) { + std::unique_lock<std::mutex> lock(m_loop->m_mutex); + m_loop->removeClient(lock); + } + if (m_loop_thread.joinable()) m_loop_thread.join(); + assert(!m_loop); + }; + std::unique_ptr<interfaces::Init> connect(int fd, const char* exe_name) override + { + startLoop(exe_name); + return mp::ConnectStream<messages::Init>(*m_loop, fd); + } + void serve(int fd, const char* exe_name, interfaces::Init& init) override + { + assert(!m_loop); + mp::g_thread_context.thread_name = mp::ThreadName(exe_name); + m_loop.emplace(exe_name, &IpcLogFn, &m_context); + mp::ServeStream<messages::Init>(*m_loop, fd, init); + m_loop->loop(); + m_loop.reset(); + } + void addCleanup(std::type_index type, void* iface, std::function<void()> cleanup) override + { + mp::ProxyTypeRegister::types().at(type)(iface).cleanup.emplace_back(std::move(cleanup)); + } + Context& context() override { return m_context; } + void startLoop(const char* exe_name) + { + if (m_loop) return; + std::promise<void> promise; + m_loop_thread = std::thread([&] { + util::ThreadRename("capnp-loop"); + m_loop.emplace(exe_name, &IpcLogFn, &m_context); + { + std::unique_lock<std::mutex> lock(m_loop->m_mutex); + m_loop->addClient(lock); + } + promise.set_value(); + m_loop->loop(); + m_loop.reset(); + }); + promise.get_future().wait(); + } + Context m_context; + std::thread m_loop_thread; + std::optional<mp::EventLoop> m_loop; +}; +} // namespace + +std::unique_ptr<Protocol> MakeCapnpProtocol() { return std::make_unique<CapnpProtocol>(); } +} // namespace capnp +} // namespace ipc diff --git a/src/ipc/capnp/protocol.h b/src/ipc/capnp/protocol.h new file mode 100644 index 0000000000..eb057949d2 --- /dev/null +++ b/src/ipc/capnp/protocol.h @@ -0,0 +1,17 @@ +// Copyright (c) 2021 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_IPC_CAPNP_PROTOCOL_H +#define BITCOIN_IPC_CAPNP_PROTOCOL_H + +#include <memory> + +namespace ipc { +class Protocol; +namespace capnp { +std::unique_ptr<Protocol> MakeCapnpProtocol(); +} // namespace capnp +} // namespace ipc + +#endif // BITCOIN_IPC_CAPNP_PROTOCOL_H |