Corium 1.1.0
High-Performance Zero-Heap C++20 MPSC Application Runtime
Loading...
Searching...
No Matches
Corium Cookbook — Real-Time Design Patterns

This guide provides tested, production-grade design patterns using Corium's zero-heap C++20 architecture.


1. Request-Response via Coroutine Event Pair

In event-driven architectures, request-response interactions avoid blocking calls by pairing request and reply events through an asynchronous task.

// 1. Define Request & Response Events
struct DataRequestEvent {
uint32_t requestId;
const char* queryKey;
};
struct DataResponseEvent {
uint32_t requestId;
int32_t resultValue;
};
using AppEvents = std::variant<
DataRequestEvent,
DataResponseEvent
>;
// 2. Coroutine Worker performing non-blocking async query
corium::async::Task<int32_t> performQuery(corium::EventSinkT<AppEvents> sink, uint32_t reqId) {
// Post request event into the lock-free event bus
sink.post(DataRequestEvent{.requestId = reqId, .queryKey = "SENSOR_ALPHA"});
// Yield execution back to event loop
// In a real system, the response handler resolves the result
co_return 42;
}
Non-blocking timer delay and yield awaitables for C++20 coroutines.
Lazy awaitable C++20 coroutine task with zero dynamic heap allocation.
void post(EventVariant &&event, EventPriority priority=EventPriority::Normal) const
Post an event into the event sink with priority (rvalue overload).
Definition EventSink.hpp:44
Lightweight C++20 coroutine task with zero-heap resumption chaining and configurable frame allocator.
Definition Task.hpp:22
Master umbrella header for the entire Corium runtime framework.
constexpr YieldAwaiter yield() noexcept
Helper to yield execution in a coroutine.
Definition Delay.hpp:25
Application shutdown event.
Definition Events.hpp:15

2. Multi-Task Coordination with <tt>whenAll</tt> and <tt>whenAny</tt>

Coordinate parallel operations deterministically without dynamic allocations.

corium::async::Task<float> readPressureSensor() {
co_return 1013.25f;
}
corium::async::Task<float> readTemperatureSensor() {
co_return 21.5f;
}
corium::async::Task<void> sampleEnvironment() {
// Wait for both sensor readings simultaneously
auto [pressure, temperature] = co_await corium::async::whenAll(
readPressureSensor(),
readTemperatureSensor()
);
std::cout << "Pressure: " << pressure << " hPa, Temp: " << temperature << " C\n";
}
Non-blocking combinator awaiting completion of multiple parallel tasks.
Non-blocking combinator resolving on the first completed task.
auto whenAll(Tasks &&... tasks)
Awaits concurrent or sequential completion of multiple Task coroutines.
Definition WhenAll.hpp:41

3. Finite State Machine with Internal Transitions and Action Lists

Execute state actions without leaving the active state or incurring exit/entry overhead.

struct StateArmed { int targetVelocity{0}; };
struct StateDisarmed {};
struct ThrottleEvent { int demand; };
struct DisarmEvent {};
struct UpdateVelocityAction {
void operator()(StateArmed& s, const ThrottleEvent& e) const {
s.targetVelocity = e.demand;
}
};
using DroneTable = corium::fsm::TransitionTable<
// Internal transition: updates velocity in-place without triggering onExit / onEnter
// External transition: moves to Disarmed
>;
Zero-heap, compile-time Finite State Machine.
Definition StateMachine.hpp:89
Umbrella header for compile-time finite state machines.
Compile-time internal transition rule (executes action without exiting or re-entering state).
Definition Transition.hpp:63
Compile-time table containing all valid state transitions.
Definition Transition.hpp:103
Compile-time transition rule definition.
Definition Transition.hpp:39

4. Structured JSON Logging for Observability

Stream high-frequency logs to JSON Lines (NDJSON) with zero allocations.

#include <fstream>
std::ofstream logFile("application.log.json");
event.timestampNs = 1700000000000000ULL;
event.category = "SAFETY_SUPERVISOR";
event.setMessage("Hardware watchdog refreshed successfully.");
jsonSink.write(event);
// Output: {"timestamp_ns":1700000000000000,"level":"INFO","category":"SAFETY_SUPERVISOR","message":"Hardware watchdog refreshed successfully."}
Structured JSON Lines (NDJSON) output log sink. Formats LogEvent records into JSON objects for struct...
Definition JsonLogSink.hpp:18
Umbrella header for the zero-heap structured logging framework.
Zero-heap log event carrying fixed-size inline message buffer across MPSC event bus.
Definition LogEvent.hpp:21
uint64_t timestampNs
Definition LogEvent.hpp:26

5. Cross-Platform Zero-Copy Shared Memory IPC

Share structured telemetry across separate OS processes without serialization overhead.

struct NavTelemetry {
double latitude;
double longitude;
float altitude;
};
using FlightIpcEvents = std::variant<corium::QuitEvent, NavTelemetry>;
// Process A: Producer daemon
producerChannel.create("/corium_flight_shm");
producerChannel.post(NavTelemetry{.latitude = 45.4642, .longitude = 9.1900, .altitude = 150.0f});
// Process B: Consumer app
consumerChannel.open("/corium_flight_shm");
FlightIpcEvents received;
if (consumerChannel.tryPop(received)) {
// Process received zero-copy event
}
High-level typed inter-process communication channel for Corium events. Encapsulates OS shared memory...
Definition IpcChannel.hpp:29
bool tryPop(EventVariant &outEvent) noexcept
Pop one event from the shared queue. Single-consumer safe.
Definition IpcChannel.hpp:87
bool post(EventType &&event) noexcept
Post an event into the shared memory queue for remote processes. Lock-free, zero-allocation,...
Definition IpcChannel.hpp:78
bool create(const std::string &channelName) noexcept
Create a new shared memory channel as the host/creator process.
Definition IpcChannel.hpp:41
Umbrella header for inter-process communication primitives.

6. Deterministic Periodic Sampling with Manual Clock Simulation

Parameterize timers with ManualClockPolicy to step time deterministically in unit tests without wall-clock sleep delays.

struct SampleTickEvent {};
using SensorEvents = std::variant<corium::QuitEvent, SampleTickEvent>;
using SimulatedRuntime = corium::RuntimeBuilder<SensorEvents>
::WithClockPolicy<corium::ManualClockPolicy>
::Build;
SimulatedRuntime runtime;
int sampleCount = 0;
runtime.reactor().template registerHandler<SampleTickEvent>([&](const SampleTickEvent&) {
++sampleCount;
});
// Schedule recurring timer every 100ms
runtime.timerScheduler().template postPeriodic<SampleTickEvent>(
std::chrono::milliseconds(100),
SampleTickEvent{}
);
// Fast-forward simulated clock by 350ms without waiting:
runtime.clockPolicy().advance(std::chrono::milliseconds(350));
runtime.pump(); // Exactly 3 ticks dispatched deterministically!
assert(sampleCount == 3);
Hardware and simulated clock policies (Chrono, Manual, Tick, EspTimer, FreeRTOS).
Fluent compile-time builder for configuring BasicRuntime. Usage: using MyRuntime = corium::RuntimeBui...
Definition RuntimeBuilder.hpp:304

7. Fault Isolation with Active Circuit Breaker

Protect critical systems against cascading failures using a zero-heap lock-free Circuit Breaker.

/* failureThreshold = */ 3,
/* cooldownPeriodNs = */ 500'000'000ULL // 500ms
);
void handleRemoteRpc() {
if (!breaker.allowExecution()) {
// Fallback: Degraded local mode without blocking
return;
}
bool success = executeHardwareI2cRead();
if (success) {
breaker.recordSuccess();
} else {
breaker.recordFailure(); // Trips to Open after 3 consecutive failures
}
}
Lock-free circuit breaker state machine for active fault isolation.
Zero-allocation Circuit Breaker pattern for isolating faulty handlers or peripheral links....
Definition CircuitBreaker.hpp:31

8. Telemetry Recording & Chrome Tracing JSON Export

Profile execution latencies in-memory and export full timeline traces for visualization in Perfetto or Google Chrome (chrome://tracing).

#include <fstream>
using ProfiledRuntime = corium::RuntimeBuilder<AppEvents>
::WithProfiler<corium::profiler::FlightRecorderProfiler<1024>>
::Build;
ProfiledRuntime runtime;
// Run application workload...
// Export traces directly to Chrome Tracing JSON file:
std::ofstream traceFile("benchmark_trace.json");
runtime.profiler().exportChromeTracingJson(traceFile);
Latency tracking and flight recording policies with runtime toggle.

9. Deterministic Event Journaling & Post-Mortem Replay

Record binary event streams with CRC-16 validation and schema hashing for deterministic black-box post-mortem replay.

#include <array>
struct SensorSample { uint32_t sensorId; float value; };
using FlightEvents = std::variant<corium::QuitEvent, SensorSample>;
// 1. Record events into static memory buffer (e.g. battery-backed SRAM / Flash)
std::array<std::byte, 4096> journalStorage{};
writer.record(SensorSample{.sensorId = 1, .value = 101.3f});
writer.record(SensorSample{.sensorId = 2, .value = 24.5f});
// 2. Replay recorded journal deterministically into a live runtime EventSink
size_t replayed = reader.replayInto(runtime.eventSink());
runtime.pump(); // Dispatches all 2 recorded events with exact payload integrity!
Zero-heap binary event journal for deterministic recording and replay.
Corium Application Runtime managing MPSC event loops and static policy execution. Zero dynamic heap a...
Definition Runtime.hpp:48
EventSinkT< EventVariant > eventSink() noexcept
Access event sink handle.
Definition Runtime.hpp:313
void pump()
Pump all pending events in the queue until empty.
Definition Runtime.hpp:133
Zero-heap event journal reader and deterministic player into Corium EventSinks.
Definition EventJournal.hpp:161
Statically allocated binary event journal writer for zero-heap post-mortem logging and record playbac...
Definition EventJournal.hpp:68

10. Hardware SPI & I2C Sensor Ingestion from ISRs

Ingest high-rate sensor transactions from hardware DMA interrupts into Corium's event bus with zero heap allocations.

struct ImuSampleEvent { int16_t accelX, accelY, accelZ; };
using EcuEvents = std::variant<corium::QuitEvent, ImuSampleEvent>;
// Ingest from SPI DMA completion ISR:
void SPI1_DMA_IRQHandler() {
// Read 6 bytes of accelerometer registers from SPI Rx DMA buffer...
rawFrame.data = {0x01, 0x00, 0x02, 0x00, 0x03, 0x00};
auto imuEvent = ImuSampleEvent{
.accelX = static_cast<int16_t>(rawFrame.data[0] | (rawFrame.data[1] << 8)),
.accelY = static_cast<int16_t>(rawFrame.data[2] | (rawFrame.data[3] << 8)),
.accelZ = static_cast<int16_t>(rawFrame.data[4] | (rawFrame.data[5] << 8))
};
runtime.isrSink().postFromIsr(imuEvent, corium::EventPriority::High);
}
Zero-heap I2C bus hardware ISR adapter for sensors and peripherals.
Zero-heap SPI hardware ISR and DMA completion adapter for embedded sensors (IMU, ADC,...
Fixed-capacity SPI transfer frame structure for zero-heap ISR and DMA ingestion.
Definition SpiAdapter.hpp:24

11. Low-Latency Zero-Copy UDP Telemetry Streaming

Send and receive framed event datagrams over Ethernet/Wi-Fi without dynamic memory allocations.

struct DroneTelemetry { float altitude; float batteryVoltage; };
using DroneEvents = std::variant<corium::QuitEvent, DroneTelemetry>;
// Sender node (e.g. Ground Control Station):
udpSender.open();
udpSender.sendEvent("192.168.1.50", 9000, DroneTelemetry{.altitude = 120.5f, .batteryVoltage = 15.8f});
// Receiver node (e.g. On-Board Companion Computer):
udpReceiver.bind(9000);
// In main event loop: receive and push directly into runtime sink
udpReceiver.receiveAndPush(runtime.eventSink());
runtime.pump();
Zero-heap UDP network channel for distributed event telemetry and IoT nodes.
Statically buffered, zero-heap UDP communication channel for distributed Corium nodes.
Definition StaticUdpChannel.hpp:48
bool sendEvent(const char *ip, uint16_t port, const Event &event) noexcept
Serialize and send a typed event over UDP using Corium WirePacket framing.
Definition StaticUdpChannel.hpp:196
bool receiveAndPush(Sink &sink, EventPriority priority=EventPriority::Normal) noexcept
Receive a WirePacket and deserialize directly into a Corium EventSink.
Definition StaticUdpChannel.hpp:248

12. Bounded Producer-Consumer Pipeline with Async Channel & Backpressure

Pass typed messages between asynchronous C++20 coroutines with compile-time backpressure.

// Create a static bounded channel with capacity of 8 items
for (int i = 1; i <= 10; ++i) {
// Suspends automatically if channel is full (backpressure)
co_await dataChannel.push(i * 100);
}
dataChannel.close();
}
while (true) {
// Suspends automatically if channel is empty
auto val = co_await dataChannel.pop();
if (!val.has_value()) {
break; // Channel closed and drained
}
std::cout << "Received: " << *val << "\n";
}
}
Zero-heap bounded asynchronous channel for C++20 coroutine message passing.
Statically allocated bounded asynchronous channel for typed producer-consumer coroutines.
Definition Channel.hpp:23
void close() noexcept
Close the channel. No more pushes will succeed. Remaining elements can still be popped.
Definition Channel.hpp:87
PushAwaiter push(T val) noexcept
Push an item into the channel asynchronously with backpressure suspension.
Definition Channel.hpp:157
PopAwaiter pop() noexcept
Pop an item from the channel asynchronously.
Definition Channel.hpp:207

13. Concurrency Throttling with Async Counting Semaphore

Limit the number of concurrent asynchronous operations without thread blocking.

// Allow maximum 2 concurrent flash write operations
corium::async::AsyncSemaphore flashWriteSemaphore(2);
corium::async::Task<void> flashWriter(int workerId) {
co_await flashWriteSemaphore.acquire(); // Suspend until permit available
std::cout << "Worker " << workerId << " writing to Flash...\n";
flashWriteSemaphore.release(); // Return permit to other waiting coroutines
}
Zero-heap asynchronous counting semaphore for C++20 coroutines.
Asynchronous counting semaphore for cooperative coroutine concurrency throttling.
Definition Semaphore.hpp:17

14. Zero-Heap Prometheus Metrics Exporter

Instrument real-time embedded applications with atomic counters, gauges, and histograms, exporting directly to Prometheus format.

#include <array>
#include <iostream>
// Define static zero-heap metrics
corium::profiler::Counter rxPackets("rx_packets_total", "Total network packets received");
corium::profiler::Gauge activeSessions("active_sessions", "Active client connections");
void onPacketReceived() {
rxPackets.increment();
activeSessions.set(5);
}
void handleMetricsHttpEndpoint() {
std::array<char, 512> buffer{};
size_t len = corium::profiler::formatPrometheusCounter(rxPackets, buffer);
std::cout.write(buffer.data(), len);
// Output:
// # HELP rx_packets_total Total network packets received
// # TYPE rx_packets_total counter
// rx_packets_total 1
}
Zero-heap Prometheus-compatible metric counters, gauges, and histograms.
Atomic 64-bit monotonically increasing counter.
Definition Metrics.hpp:22
Atomic 64-bit signed gauge metric representing instantaneous level.
Definition Metrics.hpp:55
size_t formatPrometheusCounter(const Counter &c, std::span< char > buf) noexcept
Format counter in Prometheus exposition text format into a char buffer.
Definition Metrics.hpp:141

15. Static Topic-Based Multi-Subscriber Event Fan-Out

Distribute events across multiple decoupled subscribers partitioned by Topic ID without dynamic memory allocation.

struct RadarTrack { uint32_t targetId; float rangeMeters; };
using SystemEvents = std::variant<corium::QuitEvent, RadarTrack>;
corium::EventRouter<SystemEvents, /* MaxSubscribersPerTopic = */ 4, /* MaxTopics = */ 8> router;
// Subscribe Collision Avoidance module to Topic 101 (Radar Stream)
router.subscribeEvent<RadarTrack>(101, [](const RadarTrack& track) {
if (track.rangeMeters < 50.0f) {
std::cout << "Collision Warning for Target " << track.targetId << "!\n";
}
});
// Subscribe Mission Logger to Topic 101
router.subscribeEvent<RadarTrack>(101, [](const RadarTrack& track) {
std::cout << "Logging Target " << track.targetId << "\n";
});
// Publish track event to Topic 101 (fans out to all 2 subscribers)
size_t delivered = router.publishEvent(101, RadarTrack{.targetId = 42, .rangeMeters = 35.0f});
(void)delivered;
Zero-heap topic-based multi-subscriber event routing and fan-out dispatcher.
Zero-heap static topic-based publish/subscribe router. Fans out events to multiple registered delegat...
Definition EventRouter.hpp:30
size_t publishEvent(uint32_t topicId, const Event &event) const noexcept
Publish a concrete event to all subscribers of a specific topic.
Definition EventRouter.hpp:101
bool subscribeEvent(uint32_t topicId, Callable callable) noexcept
Subscribe a typed event handler lambda to a specific topic ID.
Definition EventRouter.hpp:71

16. Guarded FSM State Transitions with Safety Predicates

Conditionally permit or reject state transitions using compile-time guard predicates.

struct IdleState {};
struct ArmedState {};
struct ArmCommand { bool keyInserted; int batteryPct; };
// Guard predicate evaluated before transition
struct PreFlightSafetyGuard {
bool operator()(const IdleState&, const ArmCommand& cmd) const noexcept {
return cmd.keyInserted && cmd.batteryPct > 20;
}
};
using SecureDroneTable = corium::fsm::TransitionTable<
>;
void tryArm() {
// Rejected by guard (battery too low) -> Remains in IdleState
fsm.process_event(ArmCommand{.keyInserted = true, .batteryPct = 10});
assert(fsm.is<IdleState>());
// Accepted by guard -> Transitions to ArmedState
fsm.process_event(ArmCommand{.keyInserted = true, .batteryPct = 95});
assert(fsm.is<ArmedState>());
}
bool process_event(const Event &event)
Process an incoming event through the state machine transition table.
Definition StateMachine.hpp:143
constexpr bool is() const noexcept
Check if current active state matches type State.
Definition StateMachine.hpp:112