Preemptive RTOS · C11 · GPL-3.0
One public header. Every feature a compile-time switch that removes code, RAM and API surface. Not one dynamic allocation inside the kernel. What a build costs is settled before it runs.
Cortex-M0 → M85 · RV32 Hazard3 · dual-core SMP
| context switch, task to task | 334 | 1.34 µs |
| mutex lock + unlock | 352 | 1.41 µs |
| timer start + stop | 319 | 1.28 µs |
| critical section, enter + exit | 43 | 0.17 µs |
| os_tick_get | 10 | 0.04 µs |
What you get
Nothing you switch off costs you a byte, and nothing the kernel needs is hidden from you.
OS_CONFIG_<FEATURE>_ENABLE removes the code, the RAM and
the API surface, not just the runtime behaviour. One config file, owned by you,
and no kernel file you are ever meant to open.
One FIFO ready list per priority plus a 32-bit bitmap. The next task is a count-leading-zeros and a list head, whatever the task count.
Task blocks, ready lists, timer objects, the log ring and the optional heap
are all static arrays. The kernel never calls malloc.
A built-in self-test exercises every enabled feature over printf
and finishes with a cycle-accurate benchmark table. It needs no application code
and no board support beyond a working printf. Flash it, read the
console, then start writing firmware.
One exception vector, PendSV on Cortex-M and the
machine software interrupt on RISC-V, plus one call from your application.
No HAL, no CMSIS dependency, no linker-script edit, and SVC
stays entirely yours.
Features
The right-hand column is the whole argument: turn one off and its code, its RAM and its API surface leave the build together.
Preemptive and priority-based: 32 levels - 30 for the application, one reserved for the idle task and one for the kernel's service tasks - with one FIFO ready list per priority and round-robin between equals over a slice you set.
Two preemption barriers that are not interchangeable. One masks interrupts, the other stops only the scheduler.
Blocking delays that yield, and cycle-counted microsecond waits that do not.
Priority inheritance always on, plus deadlock detection in development builds.
Initial and maximum count, ISR-safe to give, with the usual timeout convention.
Fixed-size items between tasks or from an ISR. Static storage, your own array, or a run-time geometry from the heap. A full queue refuses by default, or drops its oldest item so the newest reading always gets through.
Whole messages whose length varies, out of one byte budget they share. Each receive returns exactly one, whole and in order.
Wait on a set of bits, for all or any of them, clearing what matched on the way out.
A single-value mailbox inside every task's own control block. The lightest signal the kernel has.
One-shot or periodic, with callbacks on a service task rather than in the tick interrupt, so they may use kernel APIs.
A full 32-bit operation set, lock-free where the instruction set allows it and a critical section where it does not.
A coalescing first-fit allocator over a static array. Nothing is taken from
the linker heap and the kernel never calls malloc.
Overflow detection on every switch away, worst-case stack headroom, and idle-versus-busy CPU sampling.
Log calls format into a ring buffer that a service task drains, so a logging task is never blocked on the transport.
Per-task core affinity over shared ready lists. Verified on silicon on three dual-core targets, Arm and RISC-V.
Secure, non-secure or disabled per build on ARMv8-M. Compiles and its callbacks are wired, but it has not yet run on a part with the Security Extension.
Run on silicon
Every row below is a real part that has run the full suite to completion , including the dedicated cross-core stress section on the dual-core ones.
| Board | Cores | Self-test |
|---|---|---|
| Raspberry Pi Pico 2 | 2 × Cortex-M33 | passed |
| Raspberry Pi Pico 2 | 2 × Hazard3 RV32 | passed |
| Raspberry Pi Pico | 2 × Cortex-M0+ | passed |
| NUCLEO-H743ZI | Cortex-M7 | passed |
| NUCLEO-H503RB | Cortex-M33 | passed |
| NUCLEO-G431RB | Cortex-M4 | passed |
How it is put together
A change lands in exactly one of them. That is why M0 through M85 is covered by three shared port files, and why RISC-V was a new port rather than a kernel change.
kernel/
The portable core: scheduler, sync and IPC, timers, memory, log. Plain C11 with no CPU knowledge anywhere in it. Never changes with the target.
arch/
Everything a CPU actually decides: the context switch, the tick, the critical-section mask, the atomics, the low-power hooks. Changes with the instruction set.
soc/
Optional per-silicon glue: a non-CMSIS vector name, inter-core signalling, hardware spinlocks. Leave it out and the kernel builds exactly as it always has.
Getting started
It reads your board, picks the matching SoC package, copies the files you own and wires up the build. It prints the exact diff first and asks before it writes anything, and running it twice is free.
Python 3.8+ and nothing else. Offline twins read a local copy and import no networking module at all.