- Ada 92.9%
- Shell 7.1%
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:
- RPC —
Do_RPC/Do_APCover 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 aGeneric_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.cfgconfiguration language and builds each partition with the right stub flags (gnatmake, orgprbuildvia-Pfor external-library / multi-project apps), wiringStarter,TerminationandReconnectionpolicies.- 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_WORKERSfor 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.shpicks 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 theDSA_SHMShared_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
docs/users-guide.md— practical guide to writing, building, running and configuring a DSA application.docs/contract.md—exp_distcontract, wire format,RE_*checklist (PCS internals).- Simple Components: https://www.dmitry-kazakov.de/ada/components.htm
- PolyORB (DSA personality, acceptance examples): https://github.com/charlie5/PolyORB
- GARLIC (older, simpler PCS): https://github.com/reznikmm/garlic
- Ada RM Annex E; GNAT
gcc/ada/exp_dist.adb,s-rpc.ads,s-parint.ads.