1
1
Fork
You've already forked ipDSA
0
An Ada DSA implementation using Kazakov simple component inter-process streams and sockets for comms.
  • Ada 92.9%
  • Shell 7.1%
charlie5 4cb9b7a9af CHANGELOG: Windows re-run green -- 4.82 verified on all three platforms
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026年07月07日 15:19:02 +10:00
docs packaging: prefix the /usr/bin wrappers with the package name (ipdsa-*) 2026年07月07日 10:42:55 +10:00
examples shared demo: overlapping-partitions shm variant; record its FreeBSD verification 2026年07月05日 11:28:54 +10:00
packaging packaging: prefix the /usr/bin wrappers with the package name (ipdsa-*) 2026年07月07日 10:42:55 +10:00
project/source Port aDSA to Kazakov Simple Components interprocess streams 2026年07月02日 09:06:26 +10:00
scripts verify_fork: reap() polls until victims are gone, not a blind 0.2 s 2026年07月06日 12:00:20 +10:00
src cfg_builder: emit -lpthread only for non-Windows toolchains 2026年07月06日 11:49:32 +10:00
tests/cfg Port aDSA to Kazakov Simple Components interprocess streams 2026年07月02日 09:06:26 +10:00
third_party/simple_components third_party: re-vendor Simple Components at upstream 4.82 (our fixes landed) 2026年07月07日 13:54:44 +10:00
.gitignore gitignore: partition executables on Windows (*.exe) 2026年07月03日 15:10:51 +10:00
CHANGELOG.md CHANGELOG: Windows re-run green -- 4.82 verified on all three platforms 2026年07月07日 15:19:02 +10:00
CLAUDE.md CLAUDE.md: the /home/rod sibling-repo paths live on the arch-ai-forge VM 2026年07月06日 12:17:45 +10:00
COPYING.RUNTIME Port aDSA to Kazakov Simple Components interprocess streams 2026年07月02日 09:06:26 +10:00
LICENSE Port aDSA to Kazakov Simple Components interprocess streams 2026年07月02日 09:06:26 +10:00
README.md packaging: prefix the /usr/bin wrappers with the package name (ipdsa-*) 2026年07月07日 10:42:55 +10:00

Interprocess PCS for Ada's Distributed Systems Annex

A Partition Communication Subsystem (PCS) for Ada's Distributed Systems Annex (Annex E), backed by Dmitry Kazakov's Simple Components interprocess streams and the Synchronization.Interprocess.Sockets extension — a runtime replacement for the deprecated PolyORB, for same-host deployments (the partitions of a distributed program run as separate processes on one machine and talk through shared memory).

This is the sibling of aDSA (the ZeroMQ-backed PCS): the same runtime, tooling and examples, with the ZeroMQ transport swapped for Kazakov shared-memory channels — so no message broker, no sockets, no network stack; a partition-to-partition call is a write into a shared ring buffer guarded by futexes.

The compiler side (GNAT's exp_dist, which expands pragma Remote_Call_Interface, RACW, RAS and Shared_Passive into stubs) is unaffected by PolyORB's end-of-life and stays in FSF GNAT. What this project rebuilds is the runtime the generated stubs call into — the implementations of System.RPC, System.Partition_Interface and System.Shared_Storage — plus pcs_gnatdist, a gnatdist/po_gnatdist replacement that builds and wires up the partitions. It presents itself to the compiler as GARLIC_DSA (stream-based marshalling), so no PolyORB Any path is involved.

How the transport works

An endpoint is the name of a shared-memory environment (a file under /tmp), not a network address. A serving partition listens on two endpoints (ipdsa-p<pid>-r for synchronous calls, -a for asynchronous ones); the listen environment holds a mutex-guarded multiplexed control stream. A caller connects by creating a fresh socket environment — the Master side of a Synchronization.Interprocess.Sockets.Actuals pair (two ring-buffer streams plus their events) — announcing its name on the control stream and waiting for the server's hello; the server opens it as the Slave side and serves it with a reader task feeding a worker pool. Connected channels are cached per peer, exactly like the ZMQ socket cache.

Status

Feature-complete against Annex E (same-host) and validated against the real, unmodified PolyORB examples/dsa configurations:

  • RPCDo_RPC/Do_APC over interprocess streams, full Ada parameter coverage via the compiler's stream attributes.
  • RACW / RAS — remote objects and remote-access-to-subprogram, including asynchronous RACWs and task-backed objects on partitions that host no RCI.
  • Shared_Passive — distributed shared memory with three backends, selectable per package: a file backend (the default), a store server (pcs_dsm) reached over the same transport, and a shared-memory backend (DSA_SHM) where each variable lives in its own Kazakov environment as a Generic_Shared_Object, read/written in place under a futex mutex — no file I/O, no server. Backend choice is cross-checked per package through the name server, so a mixed configuration fails loudly instead of split-braining.
  • pcs_gnatdist — parses the .cfg configuration language and builds each partition with the right stub flags (gnatmake, or gprbuild via -P for external-library / multi-project apps), wiring Starter, Termination and Reconnection policies.
  • Compression (DSA_COMPRESS, zlib) and canonical XDR wire (DSA_XDR, moot on one host but kept for wire compatibility).
  • Concurrency — a worker pool serves requests in parallel (DSA_SERVE_WORKERS; DSA_APC_WORKERS for async), with per-peer channel caching.
  • Robustness — distributed quiescence detection (DSA_QUIESCE), restart recovery (Fail_Until_Restart), and the RM E.3 version-consistency check.

Dropped relative to aDSA (they are network features; shared memory has no wire to protect and no remote host to reach): cross-host transport (DSA_HOST), CurveZMQ encryption/authentication (DSA_CURVE_*, DSA_AUTH) and pcs_keygen. The security boundary is the filesystem permissions of the /tmp environment files.

Requirements

  • FSF GNAT (developed against GCC 16.1.1; the runtime override recompiles a few System.* units, which needs -gnatg).
  • zlib for the optional compression.

The needed subset of Simple Components is vendored under third_party/simple_components/ (set KAZAKOV_DIR to build against another copy), with the OS-specific interprocess base in os-linux/ and os-windows/; the Synchronization.Interprocess.Sockets extension is in project/source/.

Platforms

  • Linux — the primary, fully validated platform (futex variant of the interprocess layer).
  • Windows — a source-level port over the Win32 (os-windows) variant, intended for an MSYS2/mingw64 FSF GNAT (the build scripts and generated launchers are bash). scripts/build_rts.sh picks the variant by OS automatically (no futex shim, no -fPIC, file copies instead of symlinks). Status: the whole Windows unit stack (Win32 base + streams + sockets + PCS_IPC + s-shasto) compiles semantically clean, but it has not yet been built and run on a real Windows machine — treat it as beta and see the platform notes in the User's Guide. One semantic difference to know: Windows shared-memory environments are pagefile-backed kernel objects that vanish when the last process using them exits, so the DSA_SHM Shared_Passive backend only holds values while some partition keeps them open (fine for overlapping partitions; a writer-exits-then-reader-starts pattern needs the file or DSM backend on Windows). The transport is unaffected — connections only matter while both ends live.

Quick start

# 1. Build the gnatdist replacement (a normal program; uses the stock runtime)
bash scripts/build_gnatdist.sh
# 2. Build + run a configuration. pcs_gnatdist builds the custom runtime
# (and the name server) automatically on first use / after any src change.
build/pcs_gnatdist examples/gd-echo/gd-echo.cfg
bash examples/gd-echo/run_gd.sh # -> result = 42, clean shutdown

The custom GARLIC runtime is assembled automatically; to (re)build it explicitly or use a prebuilt one, bash scripts/build_rts.sh and set DSA_RTS=<dir>. Run the whole fork corpus both build paths with bash scripts/verify_fork.sh.

For a full walkthrough — writing, building, running and configuring your own distributed application — see the User's Guide .

Install (Arch Linux)

A packaging/PKGBUILD is provided:

mkdir -p /tmp/ipdsa && cp packaging/PKGBUILD /tmp/ipdsa/ && cd /tmp/ipdsa && makepkg -si

It installs ipdsa-gnatdist, ipdsa-nameserver and ipdsa-dsm (in /usr/bin; the names are prefixed so the aDSA sibling package can be installed alongside), with sources + examples under /usr/lib/ipdsa and /usr/share/doc/ipdsa. Then just ipdsa-gnatdist <cfg> from any writable directory.

The GARLIC runtime is coupled to the gcc-ada it is built against, so a pacman hook (re)builds it in place automatically — on install and on every gcc-ada upgrade (much like dkms rebuilds kernel modules), keeping it matched to the toolchain with no user action. To rebuild it by hand after a toolchain change, sudo /usr/lib/ipdsa/rebuild-rts.sh.

Layout

src/pcs/ the PCS runtime (spliced into a custom RTS):
 s-rpc, s-parint, s-shasto -- System.* overrides
 pcs_ipc -- channels/servers over interprocess streams
 pcs_transport-- addressing, framing, serve pools, caching
 pcs_zlib -- zlib binding (the gnatdist "zip filter")
 pcs_config -- per-partition aDSA.config loader
src/nameserver/ pcs_nameserver (bootstrap/name service), pcs_dsm (shared store)
src/gnatdist/ pcs_gnatdist -- the .cfg-driven build tool
project/source/ Synchronization.Interprocess.Sockets (+ .IO) -- the
 Master/Slave socket abstraction over Kazakov streams
third_party/ vendored Simple Components subset (see its README)
scripts/ build_rts.sh, build_nameserver.sh, build_gnatdist.sh, verify_fork.sh
examples/ demos + the real PolyORB examples/dsa configs (dsa-echo, dsa-bank,
 dsa-mailboxes, ...) plus feature demos (concurrent, quiesce,
 restart, version, bench-pool, ...)

Opt-in runtime switches

All off by default; set uniformly across a deployment. Each switch is an environment variable, but a partition can instead (or also) read them from an aDSA.config file in its own folder (next to its executable; the current directory is a fallback) — handy for giving each partition its own settings without exporting env vars. It is a list of KEY=VALUE lines (# comments and blank lines ignored); only DSA_* keys (and SHARED_MEMORY_DIRECTORY) are honoured, the file overrides the environment, and an empty value (DSA_COMPRESS=) unsets an inherited one. For example:

# examples/echo/bin/aDSA.config
DSA_COMPRESS=1
DSA_SERVE_WORKERS=16
DSA_DSM_SERVER=ipdsa-dsm
Variable Effect
DSA_NAME_SERVER=<name> the name server's endpoint name (default ipdsa-ns)
DSA_XDR=1 (build) canonical XDR wire (kept for aDSA wire compatibility)
DSA_COMPRESS=1 zlib-compress payloads
DSA_SERVE_WORKERS=N / DSA_APC_WORKERS=N serve-pool sizes
DSA_SOCKET_CACHE=0 disable per-peer channel caching
DSA_QUIESCE=1 distributed quiescence-based termination
DSA_DSM_SERVER=<name> route Shared_Passive through the store server (default off)
DSA_SHM=1 Shared_Passive in shared memory (futex-locked, no server)
DSA_SHM_PACKAGES=pkg[:cap],... shared-memory backend for just these packages
DSA_SHM_MAX_BYTES=N default per-variable cap for DSA_SHM (default 64K, max 1M)

Licensing

Distributed under the GNU General Public License v3.0 with the GCC Runtime Library Exception — the same terms the GNAT runtime carries. See LICENSE for the GPLv3 and COPYING.RUNTIME for the exception (GCC RLE 3.1).

Because the PCS is spliced into the GNAT runtime and linked into every distributed program, the exception matters: a program built with ipDSA is not forced under the GPL — you may license your own application however you like, exactly as you can with the stock GNAT runtime.

Some files are derived from the GNAT run-time library (src/pcs/s-rpc.*, src/pcs/s-parint.*, src/pcs/s-shasto.adb) and carry that same lineage. The vendored Simple Components subset is GM-GPL (GPL + linking exception; see third_party/simple_components/README.md). The reference DSA personality and acceptance-test corpus come from the charlie5/PolyORB fork.

Reference