ZeroDDS-SHM-Transport 1.0 — Spec Coverage
A ZeroDDS-vendor-specific shared-memory transport. Analogous to Cyclone’s iceoryx integration, FastDDS SHM and RTI DDS SHM. Not OMG-normative. Implemented in:
crates/transport-shm/· docs.rs — segment layout + SPSC ring buffer + crash recovery (posix.rs)
The vendor-reserved locator-kind value (§9.4) is a constant in
crates/rtps/src/wire_types.rs.
| Spec family | Status |
|---|---|
| OMG-normative | DDSI-RTPS 2.5 §9.4 LocatorKind (vendor-reserved range) — locator value in crates/rtps/src/wire_types.rs |
| ZeroDDS-own spec | segment layout + SPSC ring buffer + crash recovery — zerodds-shm-transport-1.0.md |
§1 Scope and spec status
§1.1 What OMG standardizes
For SHM, DDSI-RTPS 2.5 standardizes only:
- §9.4 LocatorKind: vendor-reserved values for non-IP transports. The
ZeroDDS value is in
crates/rtps/src/wire_types.rs.
No normative wire format, no normative segment layout, no normative cleanup protocol.
§1.2 What OMG does not standardize
- Segment layout: vendor-specific.
- Synchronization model (SPSC / SPMC / mutex): vendor-specific.
- Crash recovery: vendor-specific.
- Cleanup mechanics: vendor-specific.
- Multi-reader distribution: vendor-specific.
§1.3 ZeroDDS choice
The ZeroDDS SHM transport defines its own spec (this file) for segment layout + synchronization. The spec is:
- OMG-conformant at the locator level (§9.4 vendor-reserved value).
- Vendor-specific at the wire/synchronization level (analogous to iceoryx/FastDDS-SHM/RTI).
§2 Segment layout
offset 0: magic: u32 BE "ZSHM" (0x5A53484D)
offset 4: version: u32 LE
offset 8: capacity: u64 LE (data region, excluding header)
offset 16: head: AtomicU64 (next write offset, writer-owned)
offset 24: tail: AtomicU64 (next read offset, reader-owned)
offset 32: shutdown: AtomicU32 (0=active, 1=owner-gone)
offset 36: reserved (padding to a 64-byte cache line)
offset 64: data region [capacity bytes]
- Magic
"ZSHM"— a version discriminator; rejects foreign segments. - Version: currently
1. Bumped on a layout change; openers reject unknown versions. - Head/tail:
AcqRelatomics for lock-free single-producer single-consumer synchronization. - Shutdown: an owner→consumer termination signal (the owner sets it to
1inDrop).
Repo anchors: crates/transport-shm/src/posix.rs::HEADER_BYTES,
SHM_MAGIC, SHM_VERSION.
§3 Frame format
A length-prefix format inside the data region:
+---------+---------+---------+---------+----- ...
| len: u32 LE | bytes [len]
+---------+---------+---------+---------+----- ...
len = 0xFFFF_FFFEmarks a padding frame (a ring-end marker). The writer inserts it when there is not enough contiguous space at the ring end; it then jumps to the start.len < capacityis a data frame.
Repo anchors: posix.rs::PADDING_FRAME_LEN,
posix.rs::SegmentLayout::push_frame,
posix.rs::SegmentLayout::pop_frame.
§4 Synchronization model
§4.1 Single-producer single-consumer
One segment per (owner, consumer) pair — not one segment per owner with a
multi-reader fan-out.
Rationale:
- Lock-free SPSC scales linearly with the reader count, with no global
contention.
- A pthread_mutex with PTHREAD_PROCESS_SHARED would be the alternative,
but it is crash-recovery-fragile.
- SPMC (like iceoryx) blocks the writer on the slowest reader — bad with
heterogeneous readers.
Cost: N segments for N readers. With 100 readers × 1 MiB default = 100 MiB. Acceptable; the per-pair segment size is configurable.
§4.2 Memory ordering
- Writer:
Releasestore onheadafter the frame write. - Reader:
Acquireload ofheadbefore the frame read. - Guaranteed: the writer-side frame bytes are visible as soon as the reader
sees the new
headvalue.
Repo anchors: posix.rs::SegmentLayout::head / SegmentLayout::tail.
§5 Cleanup semantics
§5.1 Predictable os_id
segment_os_id(owner, consumer) returns a deterministic segment name
(/zd-<owner>-<consumer> or /zd-<owner-tail15>-<consumer-tail15> on the
macOS PSHMNAMLEN).
Repo anchor: posix.rs::segment_os_id.
§5.2 Crash recovery
Before every owner create(), shm_unlink(os_id) is called. This:
- reclaims zombie segments of a crashed owner.
- is idempotent (ENOENT is ignored).
- prevents a system-wide /dev/shm leak.
Repo anchor: posix.rs::shm_unlink_by_os_id.
§5.3 Shutdown flag
The owner sets shutdown = 1 in Drop (Release store). The consumer checks
the flag in wait_for_frame after every empty poll and returns with a
targeted error (Io{message:"shm owner terminated"}) instead of falling
blindly into recv_timeout.
Repo anchors: posix.rs::SegmentLayout::set_shutdown,
posix.rs::SegmentLayout::is_shutdown.
§5.4 Race protection on owner create
An exclusive whole-file lock on a sentinel file serializes parallel owner
creates on the same os_id — across threads AND processes. Linux/macOS via
flock(LOCK_EX), Windows via LockFileEx (LOCKFILE_EXCLUSIVE_LOCK,
blocking). Both auto-release on handle close / process death (identical
crash-resilience).
Repo anchors: posix.rs::acquire_flock_excl, posix.rs::FlockGuard.
§6 Platform support
| Platform | Status | Notes |
|---|---|---|
| Linux | ✅ primary | full test coverage |
| macOS | ✅ supported | PSHMNAMLEN limit observed |
| Windows | ✅ supported | zero-copy SHM via shared_memory (CreateFileMapping); owner-create race via LockFileEx; cleanup via OS handle reference counting. Test suite green on Windows (19/19, incl. open_concurrent_two_threads_both_bound) |
| no_std | not supported | std-only (mmap needs OS calls) |
§7 Test coverage
| Spec section | Tests |
|---|---|
| §2 segment layout | posix.rs::tests::magic_and_layout_* |
| §3 frame format | posix.rs::tests::push_pop_*, padding_* |
| §4 SPSC synchronization | posix.rs::tests::concurrent_* |
| §5.2 crash recovery | posix.rs::tests::recovers_zombie_segment |
| §5.3 shutdown flag | posix.rs::tests::owner_drop_signals_consumer |
| §5.4 race protection | posix.rs::tests::flock_* |
| §6 cross-process | tests/l1_cross_process.rs |
Total: 19 lib + 1 integration = 20 tests. All green on Linux, macOS and
Windows (cargo test -p zerodds-transport-shm).
§8 Status
Fully covered. The ZeroDDS SHM transport is a complete, internally coherent spec; all § sections are implemented and tested. Platform support: Linux (primary), macOS and Windows — all three with a green test suite.
ZeroDDS-SHM-Transport 1.0 — Spec-Coverage
ZeroDDS-vendor-spezifischer Shared-Memory-Transport. Analog zu Cyclone’s iceoryx-Integration, FastDDS-SHM und RTI-DDS-SHM. Nicht OMG-normativ. Implementiert in:
crates/transport-shm/· docs.rs — Segment-Layout + SpSc-Ringbuffer + Crash-Recovery (posix.rs)
Der vendor-reservierte Locator-Kind-Wert (§9.4) ist eine Konstante in
crates/rtps/src/wire_types.rs.
| Spec-Family | Status |
|---|---|
| OMG-normativ | DDSI-RTPS 2.5 §9.4 LocatorKind (vendor-reserved range) — Locator-Wert in crates/rtps/src/wire_types.rs |
| ZeroDDS-eigene Spec | Segment-Layout + SpSc-Ringbuffer + Crash-Recovery — zerodds-shm-transport-1.0.md |
§1 Scope und Spec-Status
§1.1 Was OMG normiert
DDSI-RTPS 2.5 normiert für SHM nur:
- §9.4 LocatorKind: vendor-reservierte Werte für nicht-IP-
Transports. ZeroDDS-Wert in
crates/rtps/src/wire_types.rs.
Kein normatives Wire-Format, kein normatives Segment-Layout, kein normatives Cleanup-Protokoll.
§1.2 Was OMG nicht normiert
- Segment-Layout: vendor-spezifisch.
- Synchronisations-Modell (SpSc / SpmC / Mutex): vendor-spezifisch.
- Crash-Recovery: vendor-spezifisch.
- Cleanup-Mechanik: vendor-spezifisch.
- Multi-Reader-Distribution: vendor-spezifisch.
§1.3 ZeroDDS-Wahl
ZeroDDS-SHM-Transport definiert eine eigene Spec (diese Datei) für Segment-Layout + Synchronisation. Die Spec ist:
- OMG-konform auf Locator-Ebene (§9.4 vendor-reservierter Wert).
- Vendor-spezifisch auf Wire-/Synchronisations-Ebene (analog iceoryx/FastDDS-SHM/RTI).
§2 Segment-Layout
offset 0: magic: u32 BE "ZSHM" (0x5A53484D)
offset 4: version: u32 LE
offset 8: capacity: u64 LE (Daten-Region, ohne Header)
offset 16: head: AtomicU64 (nächster Schreib-Offset, Writer-owned)
offset 24: tail: AtomicU64 (nächster Lese-Offset, Reader-owned)
offset 32: shutdown: AtomicU32 (0=active, 1=owner-gone)
offset 36: reserved (padding zu 64-Byte cache-line)
offset 64: data-region [capacity bytes]
- Magic
"ZSHM"— Versions-Discriminator, lehnt fremde Segmente ab. - Version: aktuell
1. Bump bei Layout-Änderung; Opener lehnen unbekannte Versionen ab. - Head/Tail:
AcqRel-Atomics für Lock-free Single-Producer-Single- Consumer-Synchronisation. - Shutdown: Owner→Consumer-Termination-Signal (Owner setzt auf
1inDrop).
Repo-Anker: crates/transport-shm/src/posix.rs::HEADER_BYTES,
SHM_MAGIC, SHM_VERSION.
§3 Frame-Format
Length-Prefix-Format innerhalb der Daten-Region:
+---------+---------+---------+---------+----- ...
| len: u32 LE | bytes [len]
+---------+---------+---------+---------+----- ...
len = 0xFFFF_FFFEmarkiert ein Padding-Frame (Ring-End-Marker). Writer setzt es ein, wenn nicht genug zusammenhängender Space am Ring-Ende ist; springt danach an den Anfang.len < capacityist ein Daten-Frame.
Repo-Anker: posix.rs::PADDING_FRAME_LEN,
posix.rs::SegmentLayout::push_frame,
posix.rs::SegmentLayout::pop_frame.
§4 Synchronisations-Modell
§4.1 Single-Producer-Single-Consumer
Ein Segment pro (owner, consumer)-Paar — nicht ein Segment pro
Owner mit Multi-Reader-Fan-out.
Rationale:
- Lock-free SpSc skaliert linear mit Reader-Count, keine globale
Contention.
- pthread_mutex mit PTHREAD_PROCESS_SHARED wäre der
Alternativweg, ist aber crash-recovery-fragile.
- SpmC (wie iceoryx) blockt den Writer am slowest-Reader — bei
heterogenen Readern schlecht.
Preis: N Segmente bei N Readern. Bei 100 Readern × 1 MiB Default = 100 MiB. Akzeptabel; Segment-Größe pro Paar konfigurierbar.
§4.2 Memory-Ordering
- Writer:
Release-Store aufheadnach Frame-Write. - Reader:
Acquire-Load vonheadvor Frame-Read. - Garantiert: Writer-side Frame-Bytes sind sichtbar, sobald Reader
den neuen
head-Wert sieht.
Repo-Anker: posix.rs::SegmentLayout::head /
SegmentLayout::tail.
§5 Cleanup-Semantik
§5.1 Predictable os_id
segment_os_id(owner, consumer) liefert einen deterministischen
Segment-Namen (/zd-<owner>-<consumer> bzw. /zd-<owner-tail15>-<consumer-tail15> auf macOS-PSHMNAMLEN).
Repo-Anker: posix.rs::segment_os_id.
§5.2 Crash-Recovery
Vor jedem Owner-create() wird shm_unlink(os_id) gerufen. Dies:
- Räumt Zombie-Segmente eines crashed Owners auf.
- Ist idempotent (ENOENT wird ignoriert).
- Verhindert systemweiten /dev/shm-Leak.
Repo-Anker: posix.rs::shm_unlink_by_os_id.
§5.3 Shutdown-Flag
Owner setzt shutdown = 1 in Drop (Release-Store). Consumer prüft
das Flag in wait_for_frame nach jedem leeren Poll und kehrt mit
einem gezielten Error (Io{message:"shm owner terminated"}) zurück,
statt blind in den recv_timeout zu fallen.
Repo-Anker: posix.rs::SegmentLayout::set_shutdown,
posix.rs::SegmentLayout::is_shutdown.
§5.4 Race-Protection beim Owner-Create
Eine exklusive Whole-File-Lock auf einer Sentinel-Datei serialisiert
parallele Owner-Creates auf dieselbe os_id — über Threads UND Prozesse.
Linux/macOS via flock(LOCK_EX), Windows via LockFileEx
(LOCKFILE_EXCLUSIVE_LOCK, blockierend). Beide werden beim Schließen des
Handles bzw. Prozess-Tod automatisch freigegeben (gleiche Crash-Resilienz).
Repo-Anker: posix.rs::acquire_flock_excl,
posix.rs::FlockGuard.
§6 Plattform-Support
| Plattform | Status | Anmerkungen |
|---|---|---|
| Linux | ✅ primary | Volle Test-Coverage |
| macOS | ✅ supported | PSHMNAMLEN-Limit beachtet |
| Windows | ✅ supported | Zero-Copy-SHM über shared_memory (CreateFileMapping); Owner-Create-Race via LockFileEx; Cleanup über OS-Handle-Reference-Counting. Test-Suite grün auf Windows (19/19, inkl. open_concurrent_two_threads_both_bound) |
| no_std | nicht supported | std-only (mmap braucht OS-Calls) |
§7 Test-Coverage
| Spec-Sektion | Tests |
|---|---|
| §2 Segment-Layout | posix.rs::tests::magic_and_layout_* |
| §3 Frame-Format | posix.rs::tests::push_pop_*, padding_* |
| §4 SpSc-Synchronisation | posix.rs::tests::concurrent_* |
| §5.2 Crash-Recovery | posix.rs::tests::recovers_zombie_segment |
| §5.3 Shutdown-Flag | posix.rs::tests::owner_drop_signals_consumer |
| §5.4 Race-Protection | posix.rs::tests::flock_* |
| §6 Cross-Process | tests/l1_cross_process.rs |
Total: 19 lib + 1 integration = 20 Tests. Alle grün auf Linux, macOS und
Windows (cargo test -p zerodds-transport-shm).
§8 Status
Voll abgedeckt. ZeroDDS-SHM-Transport ist eine vollständige, in-sich-kohärente Spec; alle §-Sektionen sind implementiert und getestet. Plattform-Support: Linux (primary), macOS und Windows — alle drei mit grüner Test-Suite.