ros_sugar.robot.shm#

Shared-memory ring buffer for large robot-plugin feedback payloads.

When a plugin feedback (a camera frame, a large custom struct) has to cross the process boundary between the plugin HOST and a component under multiprocess launch, this module carries the raw payload through POSIX shared memory instead. The HOST writes the frame into a slot of a per-channel ring buffer and publishes only a tiny descriptor (segment name, slot, sequence, length) over the existing bus socket. The consumer maps the segment and copies the frame out of the slot. The big buffer never gets CDR-encoded and never streams through the socket.

Design Elements:

  • Single writer, many readers, per feedback channel. One ShmRingWriter owns each segment and is the sole party that ever unlinks it; readers only attach and close.

  • Torn-read safety is a per-slot seqlock (a state counter bumped to odd before a write and to even after) combined with a ring depth of a few slots and a reader that copies the slot out immediately. A reader that loses the race gets None (a dropped frame). It never gets corrupt bytes or a stall.

Module Contents#

Classes#

ShmDescriptor

Everything a reader needs to locate one frame in shared memory.

ShmRingWriter

The HOST side of one channel’s ring. Writes frames and hands back descriptors.

ShmReaderCache

Consumer side. Attach segments by name (cached) and copy frames out.

PluginShmManager

Owns every channel’s ShmRingWriter for one launch.

Functions#

segment_name_base

Base name for a channel’s segments; the epoch is appended per allocation.

API#

ros_sugar.robot.shm.segment_name_base(launcher_pid: int, plugin_id: str, feedback_key: str) str#

Base name for a channel’s segments; the epoch is appended per allocation.

Namespaced by launcher pid and plugin id + feedback key (unique per channel). The final name stays well under NAME_MAX for /dev/shm entries.

class ros_sugar.robot.shm.ShmDescriptor#

Everything a reader needs to locate one frame in shared memory.

pack() bytes#

Serialize to a compact msgpack blob for the bus.

class ros_sugar.robot.shm.ShmRingWriter(name_base: str, slot_count: int = DEFAULT_SLOT_COUNT, min_slot_size: int = DEFAULT_MIN_SLOT_SIZE)#

The HOST side of one channel’s ring. Writes frames and hands back descriptors.

Single-writer (each feedback channel is dispatched from one thread). The segment is created lazily on the first write, sized from the first frame and recreated if any subsequent frame outgrows the slow (should be rare).

write(buffer) ros_sugar.robot.shm.ShmDescriptor#

Copy buffer into the next slot and return its descriptor.

close() None#

Unmap and unlink the current and all retired segments. Idempotent.

class ros_sugar.robot.shm.ShmReaderCache(retries: int = _READ_RETRIES)#

Consumer side. Attach segments by name (cached) and copy frames out.

read(desc: ros_sugar.robot.shm.ShmDescriptor) Optional[bytes]#

Return the frame desc points at, or None if it was missed.

None means the slot was recycled, the writer was mid-write across every retry, or the segment is already gone. All such conditions are considered dropped frames.

close() None#

Unmap every attached segment. Idempotent.

class ros_sugar.robot.shm.PluginShmManager(launcher_pid: Optional[int] = None, slot_count: int = DEFAULT_SLOT_COUNT, min_slot_size: int = DEFAULT_MIN_SLOT_SIZE)#

Owns every channel’s ShmRingWriter for one launch.

Created by the launcher alongside the socket feedback bus and injected into each plugin HOST, which requests a per-channel writer via writer_for. Closing the manager tears down every segment.

writer_for(plugin_id: str, feedback_key: str) ros_sugar.robot.shm.ShmRingWriter#

Create shm writer certain feedback out of certain plugin

close() None#

Close and unlink every channel’s segments. Idempotent.