Architecture¶
The model the library implements: three layers, and one rule that keeps kernels out of component code.
Figure description and sources
From top to bottom. Your code uses the C++ classes (listed from include/.h). Every class calls the C portability layer, the OS_ types and os_* functions of OsAbstraction.h and OsUtility.h, and nothing else. That layer includes exactly one backend header from include/os/, chosen by a compile definition (read from the table in OsAbstraction.h); with no definition the no-RTOS backend is used, for host tests and bare metal. The backend is the only code that names a kernel.
Drawn from: include classes; include/OsAbstraction.h backend table; figure module docs/diagrams/figures/rtos-layers.py.
Layers¶
| Layer | Files | Contains |
|---|---|---|
| C++ wrappers | include/*.h, src/*.cpp |
BaseThread, RtosMutex, Mutex, MutexGuard, SignalSemaphore, OsQueue, OsEventFlags, PeriodicTimer, CriticalGuard, the generic templates, TestLogicWithTimeout |
| C portability layer | include/OsAbstraction.h, include/OsUtility.h, src/OsUtility.cpp |
The OS_* types and os_* functions: threads, queues, mutexes, semaphores, event groups, timers, stream buffers, critical sections, time |
| Backend | include/os/ |
One header per scheduler that maps the OS_* / os_* surface onto the kernel |
The rules¶
- Classes call only the C layer. No wrapper includes a kernel header;
OsAbstraction.his the only header that includes a backend. - The backend owns every kernel difference: include layout, core affinity, critical-section style and the tick source. A build selects a backend with one definition; it never force-includes a compatibility header or redefines a kernel macro.
- Public surfaces use plain C++ types. Timeouts are
uint32_tmilliseconds andUINT32_MAXwaits forever;WaitModeis anenum class. TheOS_Ulong,OS_ORandOS_WAIT_FOREVERnames stay inside the library. - This library is the bottom of the HardFOC dependency chain. It includes nothing from its sibling or parent repositories.
Memory¶
Nothing here allocates on a hot path. Allocation happens once, where a kernel object is created:
| Class | When the kernel object is created | Storage you own |
|---|---|---|
BaseThread |
CreateBaseThread(), from your Initialize() |
The stack buffer you pass |
OsQueue<T, N> |
Constructor | Inline: the kernel queue and N word-rounded items (FreeRTOS, ThreadX) |
OsEventFlags, RtosMutex, Mutex, SignalSemaphore |
Constructor or first use | None |
PeriodicTimer |
Create() |
None |
FlagsSaver, SeqlockSnapshot |
Event group on the first wait | Inline words or T |
ErrorHistory<R, N> |
Its RtosMutex |
Inline R[N] |
BaseThreadsManager |
Constructor | std::map of threads (heap) |
One call through the layers¶
sequenceDiagram
participant App as Your code
participant Q as OsQueue<Sample, 32>
participant C as OsUtility.cpp
participant B as os_freertos.h
participant K as FreeRTOS
App->>Q: Send(sample, 0)
Q->>C: os_queue_send_ex(queue, ©, ticks)
C->>B: os_queue_send(&queue, ©, ticks)
B->>K: xQueueSend(queue, ©, ticks)
K-->>App: pdTRUE or errQUEUE_FULL, returned as true or false
Next: Backends.