Kickmsg
Lock-free shared-memory messaging library for inter-process communication.
Kickmsg provides MPMC publish/subscribe over shared memory with zero-copy receive, per-subscriber ring isolation, and crash resilience — all without locks or kernel-mediated synchronization on the hot path.
Features
- Lock-free: all data paths use atomic CAS (Treiber stack, MPSC rings)
- Zero-copy receive:
SampleViewpins slots via refcount, avoiding memcpy for large payloads - Per-subscriber isolation: a slow subscriber only overflows its own ring — fast subscribers are unaffected
- Crash resilient: publisher crashes never deadlock the channel; bounded slot leaks are recoverable via GC
- Topic-centric naming: subscribers connect by topic name, not publisher identity
- Blackboard: shared-memory key/value state -- a late reader immediately sees the current value of every key, with its age and its writer's liveness; no heartbeat, no replay
- C++17, no external dependencies beyond POSIX / Win32
Channel Patterns
| Pattern | API | SHM name |
|---|---|---|
| PubSub (1-to-N) | advertise / subscribe |
/{prefix}_{topic} |
| Broadcast (N-to-N) | join_broadcast |
/{prefix}_broadcast_{channel} |
| Mailbox (N-to-1) | create_mailbox / open_mailbox |
/{prefix}_{owner}_mbx_{tag} |
| Blackboard (state) | blackboard / declare / observe |
/{prefix}_bb_{name} |
Installation
For Python (also installs the kickmsg CLI):
pip install kickmsg
Pre-built wheels are published for CPython 3.10–3.12 on Linux x86_64 / aarch64
(manylinux_2_28) and macOS 11+ (universal2). On any other platform pip will
fall back to a source build, which needs the build prerequisites.
For C++ only, see Building or use the Conan recipe in
conan/all.
Quick Start
#include <kickmsg/Publisher.h>
#include <kickmsg/Subscriber.h>
// Create a channel
kickmsg::channel::Config cfg;
cfg.max_subscribers = 4;
cfg.sub_ring_capacity = 64;
cfg.pool_size = 256;
cfg.max_payload_size = 4096;
auto region = kickmsg::SharedRegion::create(
"/my_topic", kickmsg::channel::PubSub, cfg);
// Subscribe, then publish
kickmsg::Subscriber sub(region);
kickmsg::Publisher pub(region);
uint32_t value = 42;
pub.send(&value, sizeof(value));
auto sample = sub.try_receive();
// sample->data(), sample->len(), sample->ring_pos()
Node API (topic-centric)
#include <kickmsg/Node.h>
kickmsg::Node pub_node("sensor", "myapp");
auto pub = pub_node.advertise("imu");
// Any node can subscribe by topic name alone
kickmsg::Node sub_node("logger", "myapp");
auto sub = sub_node.subscribe("imu");
Zero-copy receive
auto view = sub.try_receive_view();
// view->data() points directly into shared memory
// slot is pinned until view is destroyed
Blocking receive
auto sample = sub.receive(100ms);
// blocks via futex until data arrives or timeout
Optional payload schema descriptor
// Bake a schema descriptor into the region at creation.
kickmsg::SchemaInfo info{};
info.identity = my_identity_hash(); // user-defined bytes
info.layout = my_layout_hash(); // user-defined bytes
std::snprintf(info.name, sizeof(info.name), "my/Pose");
info.version = 2;
kickmsg::channel::Config cfg;
cfg.schema = info;
auto region = kickmsg::SharedRegion::create("/pose_topic", kickmsg::channel::PubSub, cfg);
// Any process can read it back and decide what to do on mismatch.
auto schema = region.schema();
if (schema and schema->version != 2) { /* user-defined policy */ }
The library stores the descriptor in the header but never interprets it — users choose how to compute identity/layout fingerprints and how to react to mismatches.
Blackboard (state, not stream)
A Subscriber starts at the ring's current position and sees nothing
published before it attached. When what you have is state -- a lifecycle,
a mode, a calibration -- use a blackboard: the writer publishes once and
stops, and any reader that attaches later sees the current value at once.
#include <kickmsg/Node.h>
// Writer: declares the keys it owns, publishes once, stops.
kickmsg::Node arm("arm_driver", "demo");
auto& board = arm.blackboard("robot");
auto state = board.declare("arm/state"); // labelled "arm_driver"
state.write(uint32_t{ACTIVE});
// Reader: constructed AFTER the write, reads it immediately.
kickmsg::Node hmi("hmi", "demo");
auto view = hmi.blackboard("robot").observe("arm/state");
uint32_t value = 0;
auto out = view.read(value); // out.status == blackboard::Ok
// out.updated_at_ns -> how old it is; view.owner_alive() -> is the writer up?
// Block until any key on the board changes, instead of polling.
uint64_t seq = board.change_seq();
if (board.wait(seq, 100ms)) { view.read(value); }
One declared writer per key; a key whose owner died keeps its last value and can be taken over by a restarted writer. See ARCHITECTURE.md for the protocol.
Health diagnostics and crash recovery
// Periodic health check (read-only, safe under live traffic)
auto report = region.diagnose();
// report.locked_entries, report.retired_rings,
// report.draining_rings, report.live_rings
// Repair poisoned entries (safe under live traffic)
region.repair_locked_entries();
// Reset retired rings (after confirming crashed publisher is gone)
region.reset_retired_rings();
// Reclaim leaked slots (requires full quiescence)
region.reclaim_orphaned_slots();
CLI (kickmsg)
Installing the Python wheel puts a kickmsg command on $PATH that
inspects running channels via a shared participant registry (one per
namespace, backed by a SHM region at /{namespace}_registry). Works
identically on Linux, macOS, and Windows — no /dev/shm filesystem
walk required.
kickmsg list # topic-centric enumeration
kickmsg list -o name,pub,sub,stall # ps-style column selection
kickmsg info <shm> # static header metadata
kickmsg stats <shm> # runtime counters (write_pos / dropped / lost)
kickmsg watch <shm> # top-like live view, msg/s rates (interactive; Ctrl-C to quit)
kickmsg diagnose <shm> # wraps SharedRegion::diagnose()
kickmsg repair <shm> [--locked] # run repair primitives
kickmsg schema <shm> # focused schema descriptor view
kickmsg schema-diff <a> <b> # field-by-field schema comparison
kickmsg blackboard <name> # key table: size, freshness, owner, liveness
kickmsg blackboard-watch <name> # top-like live view, updates/s per key
All subcommands accept --json for scripting.
Programmatic use (GUIs, exporters)
The same data the CLI renders is available as typed dataclasses through
kickmsg.diagnostics, so a GUI can consume it without shelling out:
from kickmsg import diagnostics as diag
for topic in diag.list_topics(namespace="kickmsg"):
print(topic.shm_name, len(topic.producers), len(topic.consumers))
stats = diag.stats("/kickmsg_telemetry")
for ring in stats.rings:
if ring.state == "live":
print(ring.write_pos, ring.dropped_count, ring.lost_count)
# Live updates (generator — caller drives the loop)
for frame in diag.watch("/kickmsg_telemetry", interval=1.0):
gui.update(frame.stats, frame.rates_msg_per_sec)
# Blackboards are addressed by (name, namespace), not by shm path
board = diag.blackboard("robot", kmsg_namespace="demo")
for key in board.keys:
print(key.key, key.value_len, key.age_seconds, key.owner_alive)
Building
Prerequisites
- C++17 compiler (GCC 10+, Clang 12+, MSVC 2019+)
- CMake 3.15+
- Conan 2.x (for test/benchmark dependencies)
Build
The project's own scripts do the dependency install and the CMake configure together, which is the least error-prone route:
scripts/configure.sh build --with=unit_tests # record the option set
scripts/setup_build.sh build # conan install + cmake configure
cmake --build build
By hand:
conan install conan/conanfile.py -of=build --build=missing -o unit_tests=True
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH=build \
-DBUILD_UNIT_TESTS=ON \
-DBUILD_EXAMPLES=ON
cmake --build build
Re-run the cmake -S . -B build line every time you re-run conan install.
Skipping it reuses the existing CMake cache, which reports the dependency as
found -- Conan: Component target declared 'GTest::gtest' -- while dropping
its include paths, so the build fails with gtest/gtest.h: No such file or directory even though Conan just said Already installed. Deleting the build
directory has the same effect.
# Run the whole suite: unit, stress, crash, stall-repair, mp-stress,
# blackboard-crash, registry-stress
ctest --test-dir build --output-on-failure
# Run C++ examples
./build/examples/hello_pubsub
./build/examples/hello_zerocopy
./build/examples/hello_broadcast
./build/examples/hello_diagnose
./build/examples/hello_schema
./build/examples/hello_schema_late_publisher
./build/examples/hello_lowlevel
./build/examples/hello_blackboard
# Run Python examples (after `pip install kickmsg`)
python examples/python/hello_pubsub.py
python examples/python/hello_camera_zerocopy.py # zero-copy with memoryview
python examples/python/hello_schema.py
python examples/python/hello_blackboard.py
python examples/python/cli_playground.py # long-running, drive the `kickmsg` CLI against it
To prove kickmsg works on your own hardware -- the validation ladder from a
quick ctest gate to a multi-hour contention soak with a single
VERDICT: ALL CLEAN -- see tests/README.md.
As a subdirectory
add_subdirectory(kickmsg)
target_link_libraries(my_app PRIVATE kickmsg)
CMake Options
| Option | Default | Description |
|---|---|---|
BUILD_UNIT_TESTS |
OFF |
Build unit and stress tests |
BUILD_EXAMPLES |
OFF |
Build example programs |
BUILD_BENCHMARKS |
OFF |
Build benchmarks (requires Google Benchmark) |
ENABLE_TSAN |
OFF |
Enable ThreadSanitizer |
Security
Shared-memory objects are created with mode 0600 (owner-only) on
Linux and macOS, so channel payloads are not readable by other users
on a multi-user host. To share channels across users, set the
KICKMSG_SHM_MODE environment variable to an octal mode (e.g.
KICKMSG_SHM_MODE=0666) in every process that creates regions —
openers are unaffected. The value is parsed once per process; an
invalid value falls back to 0600 with a warning on stderr.
Platform Support
| Platform | SharedMemory | Futex |
|---|---|---|
| Linux | shm_open / mmap |
SYS_futex |
| macOS | shm_open / mmap |
__ulock_wait / __ulock_wake |
| Windows | CreateFileMapping / MapViewOfFile |
WaitOnAddress / WakeByAddressAll |
Actively validated on Linux x86-64, Linux ARM64 (Raspberry Pi 4B, 12 h continuous stress), and Darwin ARM64 (Apple Silicon, 12 h continuous stress: 2660 passes, 0 failures, 0 reorders) via scripts/validate.sh and tests/endurance.sh.
Architecture
See ARCHITECTURE.md for the full design: shared-memory layout, concurrency model, publish/subscribe flows, crash resilience, garbage collection, and ABA safety analysis.
Troubleshooting
See TROUBLESHOOTING.md for common operational gotchas: stale segments after a crash, the diagnose/repair flow, SHM naming and length limits, permission errors, and platform-specific notes (macOS PSHMNAMLEN, Windows session isolation, Linux /dev/shm sizing).
License
Release files for kickmsg 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
Total release size: 8.6 MB
Release files / kickmsg-0.7.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | kickmsg-0.7.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
96e7e60cfd78241d253856a96fccc75e8c6c03e36d3b8535fd6e69e945ddff45
|
|
BLAKE2b-256 checksum How to use checksums |
5278be39c92d43c6c9534d5f4938fe2e315ec0dd875c58aec00a2467fc92646b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logRelease files / kickmsg-0.7.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl
| Download URL | kickmsg-0.7.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.12 Linux glibc 2.26+ ARM64 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
ae596a83423abf064fcdbd5b62e1d8fe9a8a15b4cf2d241725f79867de7063e2
|
|
BLAKE2b-256 checksum How to use checksums |
e6c57eb3c5ab4cb79c2295585192255fed5471a14ae55effdad9037015248695
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logRelease files / kickmsg-0.7.0-cp312-abi3-macosx_11_0_arm64.whl
| Download URL | kickmsg-0.7.0-cp312-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 447.9 kB |
| Tags | CPython 3.12 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
441b5ea52e9564596d9adb9f66342ff549a181fa4d50e16401da053eb05fe113
|
|
BLAKE2b-256 checksum How to use checksums |
e2524c8b67d0e6b21d151a0dea05350a4f34d2d85ffac3ffd739a9cee89f738b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logRelease files / kickmsg-0.7.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | kickmsg-0.7.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
6c8d45607c432828f2d0d5c36cc57d2954698606fc44722c19f49b75bfdd9238
|
|
BLAKE2b-256 checksum How to use checksums |
a045dc72053f94fca5440b96ae227645d089e89bd66193b4f67bf0676b1a369c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logRelease files / kickmsg-0.7.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl
| Download URL | kickmsg-0.7.0-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.11 Linux glibc 2.26+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
c7c1b26bc052c9a0b1d2dc5d52d7b6670d02a52cd9ca4291d2dc773197e605fd
|
|
BLAKE2b-256 checksum How to use checksums |
51fa2e928a6c0fc5c785a7a2375a30a0ad2d98ff96877be4b10cd89e4ab4daff
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logRelease files / kickmsg-0.7.0-cp311-cp311-macosx_11_0_arm64.whl
| Download URL | kickmsg-0.7.0-cp311-cp311-macosx_11_0_arm64.whl |
|---|---|
| Size | 447.2 kB |
| Tags | CPython 3.11 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
bbdd8f18bd0e1b7dba4ef18cfc9c289b3f41cad9ee551a3a955fc3854eca193a
|
|
BLAKE2b-256 checksum How to use checksums |
f35a391cd0ebc5f2566f3bb787b10d8ececb11d6c418a8a1f813ab12f2c30b16
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logRelease files / kickmsg-0.7.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | kickmsg-0.7.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.10 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
87f825f0523e856c426f4b8b5309bacc410541dd935254306b8063c4a3d5d9a5
|
|
BLAKE2b-256 checksum How to use checksums |
8dcf206ee79bd13cfe9254bf14c66e5865b0c502d08c8d70ced4edacd8cea0a7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logRelease files / kickmsg-0.7.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl
| Download URL | kickmsg-0.7.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 1.2 MB |
| Tags | CPython 3.10 Linux glibc 2.26+ ARM64 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
dfa4b8db5a8579dc4e4225ed050f576a06689e95591fe23fb70ef1c1822ec085
|
|
BLAKE2b-256 checksum How to use checksums |
9bcf38cf68e8833ff6a95338d6a1134cd041dd26430736799ce8a319d2a75ceb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency logRelease files / kickmsg-0.7.0-cp310-cp310-macosx_11_0_arm64.whl
| Download URL | kickmsg-0.7.0-cp310-cp310-macosx_11_0_arm64.whl |
|---|---|
| Size | 446.4 kB |
| Tags | CPython 3.10 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
e0ce0c6070ead26064b1bd4ce65a1337120abc24cb4e31648b6d29e6d7b83a3a
|
|
BLAKE2b-256 checksum How to use checksums |
85b693ab22c37bf836d86b0657e7bf95ed4712507d52bcdc0cdc86d91d17f45f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.8
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 26, 2026.
Transparency log