Corium 1.1.0
High-Performance Zero-Heap C++20 MPSC Application Runtime
Loading...
Searching...
No Matches
Runtime.hpp
Go to the documentation of this file.
1
7#pragma once
8
9#include <atomic>
10#include <chrono>
11#include <cstddef>
12#include <limits>
13#include <utility>
14
16#include "corium/EventBus.hpp"
24
25namespace corium {
26
27template <typename Derived, typename EventVariant, std::size_t MaxServices>
28class Application;
29
39template <
40 typename EventVariant = DefaultEvents,
41 typename QueuePolicy = BoundedMpscQueuePolicy<EventVariant, 1024>,
42 typename SignalPolicy = NoSignalPolicy,
43 typename StoragePolicy = DefaultStoragePolicy,
44 typename OverflowPolicy = DropNewestOverflowPolicy,
45 typename TimerStoragePolicy = DefaultTimerStoragePolicy,
46 typename ProfilerPolicy = profiler::NullProfiler
47>
49public:
50 using EventVariantType = EventVariant;
51 using EventType = EventVariant;
55 using ProfilerPolicyType = ProfilerPolicy;
56
57 enum class State : uint8_t {
58 Created,
60 Running,
63 };
64
66 : _eventBus(),
67 _state(State::Created),
68 _quitRequested(false)
69 {
70 }
71
73 {
74 shutdown();
75 }
76
77 BasicRuntime(const BasicRuntime&) = delete;
79
81 [[nodiscard]] State state() const noexcept
82 {
83 return _state.load(std::memory_order_acquire);
84 }
85
87 void detachApplication() noexcept
88 {
89 _appShutdownCb = StaticCallback{};
90 }
91
97 template <typename Derived, typename AppEvents = EventVariant, std::size_t MaxServices = 8>
99 {
101 static_assert(std::is_same_v<AppEventVariant, EventVariant>,
102 "Application EventVariant list must match Runtime EventVariant list!");
103
104 _state.store(State::Initializing, std::memory_order_release);
105 _appShutdownCb = StaticCallback{
106 [](void* appPtr) {
107 auto* app = static_cast<Derived*>(static_cast<corium::Application<Derived, AppEvents, MaxServices>*>(appPtr));
108 app->shutdownServices();
109 app->shutdown();
110 app->resetContext();
111 },
112 &application
113 };
114
115 auto ctx = applicationContext();
116 ctx.setTimerScheduler(_timerScheduler);
117 ctx.setRuntimeDetach(this, [](void* rt) noexcept {
118 static_cast<BasicRuntime*>(rt)->detachApplication();
119 });
120 application.setContext(ctx);
121
122 registerCoreHandlers();
123 application.registerHandlers();
124 _eventBus.seal();
125
126 application.initializeServices(applicationContext().eventSink());
127 application.initialize();
128
129 _state.store(State::Running, std::memory_order_release);
130 }
131
133 void pump()
134 {
135 pump((std::numeric_limits<std::size_t>::max)());
136 }
137
140 void pump(std::size_t maxEvents)
141 {
142 _timerScheduler.processDueTimers(_eventBus);
143
144 std::size_t processed = 0;
145 while (_state.load(std::memory_order_relaxed) == State::Running && !_quitRequested && processed < maxEvents) {
146 if (!_eventBus.processOne()) {
147 break;
148 }
149 processed++;
150 }
151 }
152
154 template <typename Rep, typename Period>
155 std::size_t waitAndPump(const std::chrono::duration<Rep, Period>& timeout)
156 {
157 _timerScheduler.processDueTimers(_eventBus);
158
159 if (_eventBus.empty() && !_quitRequested) {
160 _eventBus.signalPolicy().wait_for(timeout);
161 }
162
163 std::size_t processed = 0;
164 while (_state.load(std::memory_order_relaxed) == State::Running && !_quitRequested) {
165 if (!_eventBus.processOne()) {
166 break;
167 }
168 processed++;
169 }
170 return processed;
171 }
172
177 std::size_t pumpBatch(std::size_t batchSize = 16, std::size_t maxTotal = (std::numeric_limits<std::size_t>::max)())
178 {
179 _timerScheduler.processDueTimers(_eventBus);
180
181 std::size_t total = 0;
182 while (_state.load(std::memory_order_relaxed) == State::Running && !_quitRequested && total < maxTotal) {
183 std::size_t toProcess = (std::min)(batchSize, maxTotal - total);
184 std::size_t processed = _eventBus.processBatch(toProcess);
185 total += processed;
186 if (processed < toProcess) {
187 break;
188 }
189 }
190 return total;
191 }
192
195 std::size_t drain()
196 {
197 _timerScheduler.processDueTimers(_eventBus);
198 if (_state.load(std::memory_order_relaxed) != State::Running || _quitRequested) {
199 return 0;
200 }
201 return _eventBus.drain();
202 }
203
205 template <typename Rep, typename Period>
206 TimerId scheduleDelayed(EventVariant event, const std::chrono::duration<Rep, Period>& delay, EventPriority priority = EventPriority::Normal)
207 {
208 return _timerScheduler.scheduleDelayed(std::move(event), delay, priority);
209 }
210
212 template <typename DurationType>
213 TimerId scheduleDelayed(EventVariant event, DurationType delay, EventPriority priority = EventPriority::Normal)
214 requires (!std::is_same_v<DurationType, std::chrono::microseconds> && !std::is_same_v<DurationType, std::chrono::milliseconds>)
215 {
216 return _timerScheduler.scheduleDelayed(std::move(event), delay, priority);
217 }
218
220 template <typename Rep, typename Period>
221 TimerId schedulePeriodic(EventVariant event, const std::chrono::duration<Rep, Period>& interval, EventPriority priority = EventPriority::Normal)
222 {
223 return _timerScheduler.schedulePeriodic(std::move(event), interval, priority);
224 }
225
227 template <typename DurationType>
228 TimerId schedulePeriodic(EventVariant event, DurationType interval, EventPriority priority = EventPriority::Normal)
229 requires (!std::is_same_v<DurationType, std::chrono::microseconds> && !std::is_same_v<DurationType, std::chrono::milliseconds>)
230 {
231 return _timerScheduler.schedulePeriodic(std::move(event), interval, priority);
232 }
233
235 bool cancelTimer(TimerId id) noexcept
236 {
237 return _timerScheduler.cancelTimer(id);
238 }
239
241 void shutdown() noexcept
242 {
243 auto st = _state.load(std::memory_order_acquire);
244 if (st == State::Stopping || st == State::Terminated) {
245 return;
246 }
247
248 _state.store(State::Stopping, std::memory_order_release);
249 if (_appShutdownCb) {
250 auto cb = _appShutdownCb;
251 _appShutdownCb = StaticCallback{};
252 cb();
253 }
254 _state.store(State::Terminated, std::memory_order_release);
255 }
256
258 void requestQuit() noexcept
259 {
260 _quitRequested.store(true, std::memory_order_release);
261 }
262
264 [[nodiscard]] bool quitRequested() const noexcept
265 {
266 auto st = _state.load(std::memory_order_acquire);
267 return _quitRequested.load(std::memory_order_acquire) || st == State::Stopping || st == State::Terminated;
268 }
269
272 {
273 _eventBus.setOnQueueNonEmpty(callback);
274 }
275
277 [[nodiscard]] SignalPolicy& signalPolicy() noexcept
278 {
279 return _eventBus.signalPolicy();
280 }
281
283 [[nodiscard]] const SignalPolicy& signalPolicy() const noexcept
284 {
285 return _eventBus.signalPolicy();
286 }
287
289 [[nodiscard]] OverflowPolicy& overflowPolicy() noexcept
290 {
291 return _eventBus.overflowPolicy();
292 }
293
295 [[nodiscard]] const OverflowPolicy& overflowPolicy() const noexcept
296 {
297 return _eventBus.overflowPolicy();
298 }
299
301 [[nodiscard]] TimerSchedulerType& timerScheduler() noexcept
302 {
303 return _timerScheduler;
304 }
305
307 [[nodiscard]] const TimerSchedulerType& timerScheduler() const noexcept
308 {
309 return _timerScheduler;
310 }
311
313 [[nodiscard]] EventSinkT<EventVariant> eventSink() noexcept
314 {
315 return _eventBus.sink();
316 }
317
319 [[nodiscard]] ProfilerPolicyType& profiler() noexcept
320 {
321 return _eventBus.profiler();
322 }
323
325 [[nodiscard]] const ProfilerPolicyType& profiler() const noexcept
326 {
327 return _eventBus.profiler();
328 }
329
330private:
332 ApplicationContext<EventVariant> applicationContext()
333 {
335 _eventBus,
337 [](void* c) { static_cast<BasicRuntime*>(c)->requestQuit(); },
338 this
339 }
340 };
341 ctx.setTimerScheduler(_timerScheduler);
342 return ctx;
343 }
344
345 void registerCoreHandlers()
346 {
347 if constexpr (has_variant_type_v<QuitEvent, EventVariant>) {
348 _eventBus.template registerHandler<QuitEvent>([this](const QuitEvent&) {
349 _quitRequested.store(true, std::memory_order_release);
350 });
351 }
352 }
353
354 EventBusType _eventBus;
355 TimerSchedulerType _timerScheduler{};
356 StaticCallback _appShutdownCb;
357 std::atomic<State> _state{State::Created};
358 std::atomic<bool> _quitRequested{false};
359};
360
363
365template <
366 typename EventVariant = DefaultEvents,
367 typename QueuePolicy = BoundedMpscQueuePolicy<EventVariant, 1024>,
368 typename SignalPolicy = NoSignalPolicy,
369 typename StoragePolicy = DefaultStoragePolicy,
370 typename OverflowPolicy = DropNewestOverflowPolicy,
371 typename TimerStoragePolicy = DefaultTimerStoragePolicy,
372 typename ProfilerPolicy = profiler::NullProfiler
373>
375
376} // namespace corium
377
Type-erased context for application runtime introspection and lifecycle control.
Multi-producer single-consumer lock-free event bus coordinator.
Queue saturation policies (DropNewest, DropOldest, Audit, Panic).
Bounded and multi-tier priority MPSC queueing policies.
Fluent compile-time builder for custom policy-configured runtimes.
Thread wake-up policies (NoSignalPolicy, ConditionVariableSignalPolicy).
Static storage capacity policies for FastDelegate SBO inline buffers.
Timer scheduler static capacity and storage policies.
Fixed-capacity static timer scheduler for delayed and periodic events.
Compile-time type index resolution for std::variant alternative types.
Context object passed to Application providing event registration, sink access, quit requests,...
Definition ApplicationContext.hpp:32
Static CRTP base class for applications managed by Corium Runtime. Subclass Application<Derived> or A...
Definition Application.hpp:38
internal::extract_event_variant_t< EventVariantOrBus > EventVariant
Definition Application.hpp:40
Policy-configurable non-virtual event bus implementation.
Definition EventBus.hpp:35
bool empty() const
Check if event queue is empty.
Definition EventBus.hpp:137
OverflowPolicy & overflowPolicy() noexcept
Access reference to overflow policy.
Definition EventBus.hpp:187
std::size_t drain()
Drain and dispatch all currently enqueued events.
Definition EventBus.hpp:115
void setOnQueueNonEmpty(StaticCallback callback)
Set static callback for event availability when queue transitions to non-empty.
Definition EventBus.hpp:149
EventSinkT< EventVariant > sink() noexcept
Get an EventSink handle pointing to this event bus.
Definition EventBus.hpp:205
bool processOne()
Process a single event from the queue.
Definition EventBus.hpp:78
void seal()
Seal reactor handlers.
Definition EventBus.hpp:143
ProfilerPolicy & profiler() noexcept
Access reference to profiler policy.
Definition EventBus.hpp:125
SignalPolicy & signalPolicy() noexcept
Access reference to signal policy.
Definition EventBus.hpp:175
std::size_t processBatch(std::size_t maxBatch)
Process up to maxBatch events consecutively from the queue.
Definition EventBus.hpp:95
Corium Application Runtime managing MPSC event loops and static policy execution. Zero dynamic heap a...
Definition Runtime.hpp:48
ProfilerPolicyType & profiler() noexcept
Access reference to profiler policy.
Definition Runtime.hpp:319
bool cancelTimer(TimerId id) noexcept
Cancel an active timer handle.
Definition Runtime.hpp:235
BasicRuntime()
Definition Runtime.hpp:65
EventSinkT< EventVariant > eventSink() noexcept
Access event sink handle.
Definition Runtime.hpp:313
const ProfilerPolicyType & profiler() const noexcept
Access const reference to profiler policy.
Definition Runtime.hpp:325
State state() const noexcept
Access current lifecycle state of the runtime.
Definition Runtime.hpp:81
TimerId schedulePeriodic(EventVariant event, DurationType interval, EventPriority priority=EventPriority::Normal)
Schedule a recurring periodic event with native clock duration.
Definition Runtime.hpp:228
ProfilerPolicy ProfilerPolicyType
Definition Runtime.hpp:55
EventVariant EventVariantType
Definition Runtime.hpp:50
TimerSchedulerType & timerScheduler() noexcept
Access reference to timer scheduler.
Definition Runtime.hpp:301
BasicRuntime & operator=(const BasicRuntime &)=delete
BasicRuntime(const BasicRuntime &)=delete
void detachApplication() noexcept
Detach application to prevent dangling callbacks on shutdown.
Definition Runtime.hpp:87
EventVariant EventType
Definition Runtime.hpp:51
std::size_t drain()
Drain and dispatch all currently enqueued events immediately.
Definition Runtime.hpp:195
~BasicRuntime()
Definition Runtime.hpp:72
void requestQuit() noexcept
Request runtime quit.
Definition Runtime.hpp:258
OverflowPolicy & overflowPolicy() noexcept
Access reference to overflow policy.
Definition Runtime.hpp:289
State
Definition Runtime.hpp:57
void setOnQueueNonEmpty(StaticCallback callback)
Set static callback triggered when event queue transitions from empty to non-empty (0 -> 1).
Definition Runtime.hpp:271
typename internal::get_timer_clock_policy< TimerStoragePolicy >::type ClockPolicyType
Definition Runtime.hpp:53
TimerId scheduleDelayed(EventVariant event, DurationType delay, EventPriority priority=EventPriority::Normal)
Schedule a single-shot delayed event with native clock duration.
Definition Runtime.hpp:213
TimerScheduler< EventVariant, TimerStoragePolicy::max_timers, ClockPolicyType > TimerSchedulerType
Definition Runtime.hpp:54
const SignalPolicy & signalPolicy() const noexcept
Access const reference to signal policy.
Definition Runtime.hpp:283
void shutdown() noexcept
Stop runtime cleanly.
Definition Runtime.hpp:241
const TimerSchedulerType & timerScheduler() const noexcept
Access const reference to timer scheduler.
Definition Runtime.hpp:307
SignalPolicy & signalPolicy() noexcept
Access reference to signal policy.
Definition Runtime.hpp:277
void pump()
Pump all pending events in the queue until empty.
Definition Runtime.hpp:133
bool quitRequested() const noexcept
Check if runtime quit has been requested.
Definition Runtime.hpp:264
void initialize(corium::Application< Derived, AppEvents, MaxServices > &application)
Initialize runtime with target application using static CRTP dispatch.
Definition Runtime.hpp:98
void pump(std::size_t maxEvents)
Pump up to maxEvents pending events from the queue.
Definition Runtime.hpp:140
BasicEventBus< EventVariant, QueuePolicy, SignalPolicy, StoragePolicy, OverflowPolicy, ProfilerPolicy > EventBusType
Definition Runtime.hpp:52
std::size_t waitAndPump(const std::chrono::duration< Rep, Period > &timeout)
Wait for at least one event to become available (or until timeout), then pump all pending events.
Definition Runtime.hpp:155
TimerId schedulePeriodic(EventVariant event, const std::chrono::duration< Rep, Period > &interval, EventPriority priority=EventPriority::Normal)
Schedule a recurring periodic event with std::chrono duration.
Definition Runtime.hpp:221
const OverflowPolicy & overflowPolicy() const noexcept
Access const reference to overflow policy.
Definition Runtime.hpp:295
TimerId scheduleDelayed(EventVariant event, const std::chrono::duration< Rep, Period > &delay, EventPriority priority=EventPriority::Normal)
Schedule a single-shot delayed event with std::chrono duration.
Definition Runtime.hpp:206
std::size_t pumpBatch(std::size_t batchSize=16, std::size_t maxTotal=(std::numeric_limits< std::size_t >::max)())
Pump events in consecutive batches to maximize CPU cache locality.
Definition Runtime.hpp:177
Queue Policy for fixed-capacity, zero-allocation lock-free MPSC RingBuffer.
Definition QueuePolicies.hpp:43
Default host clock policy using std::chrono::steady_clock.
Definition ClockPolicies.hpp:44
Signal Policy for busy-spin / polling event loops (sub-microsecond latency, zero signaling cost).
Definition SignalPolicies.hpp:72
Zero-heap Min-Heap Timer Scheduler for delayed and periodic events. Provides O(1) earliest-due timer ...
Definition TimerScheduler.hpp:37
TimerId scheduleDelayed(EventVariant event, const std::chrono::duration< Rep, Period > &delay, EventPriority priority=EventPriority::Normal)
Schedule a single-shot delayed event with std::chrono duration.
Definition TimerScheduler.hpp:63
bool cancelTimer(TimerId id) noexcept
Cancel an active timer by its TimerId handle.
Definition TimerScheduler.hpp:109
TimerId schedulePeriodic(EventVariant event, const std::chrono::duration< Rep, Period > &interval, EventPriority priority=EventPriority::Normal)
Schedule a recurring periodic event with std::chrono duration.
Definition TimerScheduler.hpp:83
std::size_t processDueTimers(EventSink &sink, time_point now=ClockPolicy::now())
Process all due timers and post their events into target event bus or sink. Uses O(1) early exit when...
Definition TimerScheduler.hpp:137
Definition Application.hpp:16
FixedTimerStoragePolicy< 64, ChronoClockPolicy > DefaultTimerStoragePolicy
Definition TimerPolicies.hpp:24
std::variant< QuitEvent, TickEvent, UpdateEvent, ErrorEvent, SignalEvent > DefaultEvents
Default variant list of core Corium events.
Definition Events.hpp:62
EventPriority
Event priority levels for multi-priority queue policies.
Definition QueuePolicies.hpp:32
uint32_t TimerId
Definition TimerScheduler.hpp:22
FixedStoragePolicy< 8, 32 > DefaultStoragePolicy
Default storage policy (8 handlers per event type, 32 bytes inline delegate storage).
Definition StoragePolicies.hpp:24
Default Overflow Policy: Silently drop incoming new event when queue is full. Zero overhead.
Definition OverflowPolicies.hpp:20
Lightweight non-allocating static callback wrapper (function pointer + optional context argument).
Definition SignalPolicies.hpp:35
Default Profiler Policy: Zero-overhead, completely compiled out by inline empty functions.
Definition ProfilerPolicies.hpp:21