feat(ipc-runtime): extract bb::ipc, add transport helpers + codegen serve() wrapper#23478
Open
charlielye wants to merge 12 commits into
Open
feat(ipc-runtime): extract bb::ipc, add transport helpers + codegen serve() wrapper#23478charlielye wants to merge 12 commits into
charlielye wants to merge 12 commits into
Conversation
Lift the UDS + MPSC-SHM server/client primitives out of barretenberg into
a new top-level package /ipc-runtime/, parallel to /ipc-codegen/. The
runtime was already self-contained (one stale throw_or_abort.hpp include
in shm_server.hpp, never called) so this is a pure relocation.
Layout:
/ipc-runtime/
bootstrap.sh # delegates to barretenberg/cpp/'s build for now
.rebuild_patterns
cpp/
CMakeLists.txt # ipc_runtime static lib + ipc_runtime_tests
ipc_runtime/ # public headers + impl, matches include prefix
ipc_{client,server}.{hpp,cpp}
socket_{client,server}.{hpp,cpp}
mpsc_shm_{client,server}.hpp
shm_{client,server,common}.hpp
shm.test.cpp
shm/{futex,mpsc_shm,spsc_shm,utilities}.{hpp,cpp}
barretenberg/cpp/src/CMakeLists.txt picks the lib up via
add_subdirectory(${CMAKE_SOURCE_DIR}/../../ipc-runtime/cpp ...) so
in-tree consumers (bb, bb-avm, aztec-wsdb, nodejs_module, api,
ipc_bench) just retarget `#include "barretenberg/ipc/..."` to
`#include "ipc_runtime/..."` and `target_link_libraries(... ipc)` to
`... ipc_runtime`.
The shm.test.cpp gtest binary is now ipc_runtime_tests, runs as part of
barretenberg's CTest discovery, all 2 tests pass.
The next step (truly standalone build via /ipc-runtime/bootstrap.sh,
without barretenberg's CMake tree) is a follow-up: the bootstrap.sh
currently delegates to barretenberg's build, and ipc-runtime/cpp/
CMakeLists.txt still uses barretenberg_module_with_sources for gtest +
msgpack convenience. Files + namespace boundary are correct; the build
plumbing tidies up later.
Two transport-adjacent helpers lifted from aztec-wsdb's wsdb_ipc_server.cpp: - make_server(input_path, opts): picks UDS vs MPSC-SHM by path suffix (.sock → IpcServer::create_socket, .shm → create_mpsc_shm). Defaults match aztec-wsdb's production config (2 SHM clients, 4 MiB rings). - install_default_signal_handlers(server): wires SIGTERM/SIGINT to request_shutdown(), SIGBUS/SIGSEGV to close()+exit(1), plus parent-death monitoring (prctl PR_SET_PDEATHSIG on Linux, kqueue NOTE_EXIT watcher on macOS). File-scope std::atomic<IpcServer*> keeps signal handlers thread-safe. Also rename the runtime namespace bb::ipc → ipc throughout. The runtime no longer lives under barretenberg, so the bb:: prefix was historical baggage. 6 in-tree consumers updated to use the new namespace; mechanical sed.
…e-include
New CLI flag --cpp-runtime-include <prefix> tells the C++ generator to emit
a serve() wrapper that uses ipc-runtime (make_server + install_default_signal_handlers
+ IpcServer::run) instead of the lightweight header-only ipc_server.hpp template.
Concretely, with --cpp-runtime-include ipc_runtime the generated <service>_ipc_server.hpp:
- #includes ipc_runtime/{ipc_server,serve_helper,signal_handlers}.hpp instead
of the bundled ipc_server.hpp template
- emits serve(input_path, ctx) that calls ipc::make_server() (UDS vs MPSC-SHM
by path suffix), installs default lifecycle signal handlers, and runs
IpcServer::run() with a lambda that adapts the codegen's DispatchHandler
(vector-of-bytes single-arg signature) to ipc::IpcServer::Handler's
(client_id, span) signature.
When --cpp-runtime-include is unset, the default header-only fallback path
is unchanged — verified by the 18-test cross-language echo matrix still
passing.
Also rename make_<service>_handler's return type from ::ipc::Handler to a
service-local DispatchHandler typedef. The legacy ::ipc::Handler only
existed in the lightweight template; the runtime defines a differently-
shaped IpcServer::Handler, so emitting a stable service-namespace name
decouples the two backends.
barretenberg_module's bench codepath links MODULE_DEPENDENCIES only to the final executable, not to the *_bench_objects OBJECT library that holds the compiled .cpp.o. Existing bench deps all lived under barretenberg/cpp/src/, which is already on -I project-wide, so they didn't trip on this. ipc_runtime is the first bench dep with headers outside that root (at /ipc-runtime/cpp/), so its `target_include_directories` only reaches consumers that link it. Add an explicit target_link_libraries(ipc_bench_objects PRIVATE ipc_runtime) to thread the include directory in. Doesn't touch the general module macro since fixing it for all modules has broader blast radius than this PR warrants.
The bb::ipc → ipc_runtime path rewrite in PR-RUNTIME's first commit swept .cpp/.hpp files but missed the .ts emitter that produces wsdb's autogenerated client header. The tracked wsdb_ipc_client_generated.hpp got the new include path; cpp_codegen.ts kept the old one. CI's noir contracts build runs \`yarn generate\` mid-run, which rewrote the tracked header back to the old path, tripping cache_content_hash's \"changes during CI run\" guard. Update cpp_codegen.ts to match. Regenerating now produces a header identical to what's tracked.
…plain CMake The ipc-runtime library has no barretenberg dependency (POSIX + std + a pthread find_package), but the previous CMakeLists used barretenberg's module macro, which dragged in Tracy/TBB/lmdb plumbing and made the package non-standalone-buildable. Replace with plain CMake. The new CMakeLists works two ways: - Top-level standalone: \`cmake -B build -S cpp && cmake --build build\` (declares its own project, sets C++20 + PIC, fetches gtest v1.13.0 via FetchContent only when tests aren't already in scope). - As an add_subdirectory() from a larger tree (e.g. barretenberg/cpp): skips project() declaration so it inherits the parent's project name and compile options; reuses the parent's GTest::gtest_main target if one is already defined. ipc-runtime/bootstrap.sh now invokes cmake directly instead of delegating to barretenberg's build. Cross-compile is via standard CMake knobs (CXX, CXXFLAGS, CMAKE_TOOLCHAIN_FILE) — e.g. zig-c++.sh + -target aarch64-linux-gnu works without extra plumbing. Verified: - Under barretenberg/cpp/'s tree: ninja ipc_runtime ipc_runtime_tests bb aztec-wsdb all build; ipc_runtime_tests 2/2 passing. - Standalone: ./bootstrap.sh produces libipc_runtime.a + ipc_runtime_tests from a clean checkout; 2/2 passing. gtest is fetched on first run.
…y templates
Codegen no longer carries its own minimal UDS-only transport for C++.
Generated client and server both depend on ipc-runtime headers and pick
UDS vs MPSC-SHM by path suffix (".sock" / ".shm").
- `ipc::make_client(path, shm_client_id)` added in serve_helper, mirror
of make_server.
- Generated <Service>IpcClient constructor takes a path, calls
ipc::make_client(path), throws on unrecognised suffix.
- Generated client's send<Cmd, Resp> uses IpcClient::{send, receive,
release} instead of the lightweight template's call(). Copies bytes
out before release for clean lifetime management.
- Generated <service>_ipc_server.hpp unconditionally uses ipc::make_server
+ install_default_signal_handlers + IpcServer::run. Dropped the
--cpp-runtime-include flag + the runtimeInclude option + the conditional
emission.
- Deleted templates/cpp/{ipc_client,ipc_server}.hpp; copyTemplate calls
removed from generate.ts cpp path.
- Echo example's C++ build (ipc-codegen/bootstrap.sh) links libipc_runtime.a;
THROW/RETHROW defined so barretenberg's patched msgpack-c compiles
outside its own tree.
Verified: ipc-codegen cross-language matrix 18/18 green via the shared
runtime; barretenberg's bb, bb-avm, aztec-wsdb, nodejs_module, ipc_runtime_tests
all build.
Plain-C extern "C" surface that wraps IpcServer and IpcClient (plus the make_server/make_client/install_default_signal_handlers helpers) so non-C++ consumers — Rust and Zig bindings landed next — can drive the same UDS + MPSC-SHM transport. The header (c_abi.h) is includable from any C99+ compiler: opaque ipc_server_t* / ipc_client_t* handles, status codes instead of exceptions, (ptr, len) pairs instead of std::span, free function pointers instead of std::function. The .cpp owns C++ <-> C marshalling. Surface mirrors the C++ API closely; see header for lifetime contracts (handler-owned response buffers, runtime-owned receive views released explicitly by the caller).
Safe wrappers around c_abi.h. Drop-impl release for both IpcServer and IpcClient, idiomatic Result<_, Error> for fallible ops, FnMut closure bridging in run() via a static shim that re-casts a *mut c_void back to the closure pointer. The build script honours IPC_RUNTIME_LIB_DIR (default: ../cpp/build), links libipc_runtime.a + libstdc++ (linux) / libc++ (macos) + pthread. Per-target archives produced by the C++ build feed the right one for cross-compile without changes to the crate. Verified by a manual smoke (UDS server + client, single round-trip with byte reversal) — checked in via cargo's example mechanism during bring-up, removed after passing. The cross-language matrix becomes the permanent regression net in the next commit. No external Rust deps; only thing the crate touches outside std is the C archive.
… template
Rust generated client/server now talks to the shared ipc-runtime
transport instead of its own per-service UDS templates.
- `templates/rust/backend.rs` keeps the `Backend` trait (the FFI backend
still uses it), but gains a single impl block bridging
`ipc_runtime::IpcClient` so the codegen-emitted `<Service>Api` can be
constructed directly with a runtime client: `Api::new(IpcClient::from_path(p))`.
- Deleted `templates/rust/{ipc_server.rs, uds_backend.rs}`; copyTemplate
calls for them removed from `generate.ts`.
- Echo example rewritten: `echo_server.rs` calls `IpcServer::from_path` +
`listen` + `run(|client_id, payload| { ... })`; `echo_client.rs`
constructs `IpcClient::from_path` and hands it to `EchoApi::new`.
- Echo `Cargo.toml` depends on the local `ipc-runtime` crate.
- `ipc-codegen/bootstrap.sh` builds ipc-runtime up front (once) and
exports `IPC_RUNTIME_LIB_DIR` for cargo to find the archive.
18-test cross-language matrix passes; all Rust pairs now go through the
shared C ABI runtime end-to-end.
… impl The generated <Service>IpcClient .cpp transitively includes msgpack-c via msgpack_struct_map_impl.hpp. Barretenberg's patched msgpack-c expects THROW/RETHROW to be defined (it uses them in place of bare `throw`). The server header already guards with #ifndef THROW; mirror it in the client impl so any consumer that compiles outside barretenberg's project- wide -DTHROW=throw still builds.
…hive Each consumer (Rust crate, Zig package, ipc-codegen's echo C++ build) now compiles ipc-runtime/cpp/ipc_runtime/*.cpp directly with its own toolchain. This eliminates the libstdc++/libc++ ABI mismatch that made a shared libipc_runtime.a unusable across language ecosystems, and removes the IPC_RUNTIME_LIB_DIR coordination requirement. - ipc-runtime/rust: build.rs uses cc::Build to compile the C++ sources into the crate's archive (cargo picks the stdlib). - ipc-runtime/zig: new package; build.zig compiles the same sources via Zig's bundled clang + libc++. - ipc-codegen/bootstrap.sh: C++ echo binaries inline the .cpp sources into each clang invocation. Cross-process IPC interop is stdlib-agnostic — wire format is bytes; SHM uses raw atomics + uint64 offsets, not std::-typed structs. Verified: full 18-test cross-language matrix (4x4 + 2 golden) passes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lifts barretenberg's
bb::ipctransport runtime out into a new top-level package/ipc-runtime/, peer to/ipc-codegen/. Three logical chunks landed as separate commits in this PR.Stacks between #23314 (ipc-codegen package) and #23316 (bb.js + wsdb consumer migration). #23316 needs rebasing on top.
A. Extract
bb::ipc→/ipc-runtime/cpp/3,449 LOC moved verbatim from
barretenberg/cpp/src/barretenberg/ipc/(incl.shm/subdir,shm.test.cpp, README) to/ipc-runtime/cpp/ipc_runtime/. Audit confirmed the module had one non-trivial external coupling — a stalethrow_or_abort.hppinclude inshm_server.hppthat was never actually called — which is dropped here.The lib is consumed by barretenberg's CMake via
add_subdirectory(${CMAKE_SOURCE_DIR}/../../ipc-runtime/cpp ...). 6 in-tree consumers retargeted (path rewrite + CMake link nameipc→ipc_runtime):nodejs_module/msgpack_client/api/api_msgpack.{hpp,cpp}+ CMakebb/CMakeLists.txt(bb + bb-avm link lines)wsdb/{CMakeLists.txt, wsdb_ipc_server.cpp}+wsdb_client/CMakeLists.txtbenchmark/ipc_bench/Namespace rename
bb::ipc::→ipc::throughout — the runtime no longer lives under barretenberg, so the bb:: prefix was historical baggage.shm.test.cppruns asipc_runtime_testsunder barretenberg's CTest, all 2 tests pass.B. Transport helpers
ipc::make_server(input_path, opts)— picks UDS vs MPSC-SHM by path suffix (.sock/.shm), matching today's hand-rolled logic inwsdb_ipc_server.cpp. Defaults match aztec-wsdb's production config (2 SHM clients, 4 MiB rings).ipc::install_default_signal_handlers(server)— SIGTERM/SIGINT → graceful shutdown, SIGBUS/SIGSEGV → close+exit, prctlPR_SET_PDEATHSIGon Linux, kqueue NOTE_EXIT watcher on macOS. Lifted fromwsdb_ipc_server.cpplifecycle code.Both pure additions; no current consumer changes.
C. Codegen
serve()wrapperNew CLI flag
--cpp-runtime-include <prefix>(e.g.ipc_runtime) tells the C++ generator to emit aserve()that uses ipc-runtime:When the flag is unset, the lightweight header-only
ipc_server.hpptemplate path is unchanged — verified by the 18-test cross-language echo matrix still passing.Also rename
make_<service>_handler's return type from::ipc::Handlerto a service-localDispatchHandlertypedef; the legacy::ipc::Handleronly existed in the lightweight template, the runtime defines a differently-shapedIpcServer::Handler, so a stable service-namespace name decouples the two backends.Out of scope (future work)
/ipc-runtime/cpp/(its own CMakeLists withoutbarretenberg_module_with_sources, FetchContent gtest, standalonebootstrap.sh). Today the build still relies on barretenberg's CMake tree for convenience.refactor(wsdb): use codegen-emitted serve()— collapseswsdb_ipc_server.cppto ~30 LOC. Belongs after Stack B PR_B6 (wire/domain split)./ipc-runtime/{rust,zig}/). Defer until a second-language server consumer materialises.Test plan
cd ipc-codegen && ./bootstrap.sh test— 18/18 echo matrix green (default header-only path)--cpp-runtime-include ipc_runtimeagainst ipc-runtime — compilesninja ipc_runtime ipc_runtime_tests+./bin/ipc_runtime_tests— 2/2 passingninja bb bb-avm aztec-wsdb— all build with retargeted link names