A deterministic, preemptive real-time operating system kernel in C++, built host-first and ported to ARM Cortex-M.
niyata (Sanskrit, नियत): fixed, regulated, determined.
Niyata is a small RTOS kernel written to understand, and demonstrate, how real-time schedulers actually work: context switching, priority-based preemption, synchronization primitives, and the classic priority inversion problem. It is developed in two stages: a fully testable simulation on Linux, then a port to real hardware (STM32, Cortex-M).
The design goal is determinism: bounded, predictable worst-case latency, rather than best average throughput.
Active development. Track progress in the roadmap below.
| Feature | Status |
|---|---|
| Portable port layer (platform-independent core) | Done |
| Task control blocks and context switching | Done |
| Cooperative round-robin scheduling | Done |
Simulated, tick-driven clock and sleep |
Done |
| Fixed-priority preemptive scheduling (O(1) task selection) | Done |
| Mutex and counting semaphore | Done |
| Priority inheritance | Done |
| Fixed-block pool allocator | Done |
| Latency and jitter benchmarks (p50 / p99 / max) | Done |
| Cortex-M port (SysTick, PendSV) | Planned |
- Deterministic first. Worst-case behaviour is measured and reported, not just averages.
- Portable core. The scheduler never touches platform headers. Everything platform-specific lives behind a small port interface, so the same core runs on a Linux simulation and on Cortex-M.
- Testable. On the host, time is simulated and tick-driven, so scheduling behaviour is reproducible and covered by unit tests.
- Small and readable. The kernel is meant to be read end to end.
+-----------------------------+
| Application tasks |
+--------------+--------------+
|
+--------------v--------------+
| Niyata core (src/) |
| scheduler | clock | sync |
+--------------+--------------+
| port.hpp
+--------------v--------------+
| Port layer |
| host: ucontext |
| cortex-m: PendSV + asm |
+-----------------------------+
include/niyata/ public headers
src/ platform-independent kernel core
port/host/ host port (POSIX ucontext)
port/cortex_m/ Cortex-M port (assembly context switch)
tests/ GoogleTest unit tests
bench/ latency and jitter benchmarks
examples/ small demos
docs/ design notes and build plan
The host build requires Linux or WSL2 (the simulation uses ucontext, which needs glibc).
sudo apt install -y build-essential cmake git gdb clang
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
ctest --test-dir build --output-on-failure
./build/hello_tasks
./build/priority_inversion_demoExpected output of the demos:
hello_tasks output:
A0 B0 A1 B1 A2 B2 done
-------------------------------------------------------
priority_inversion_demo output:
== priority inheritance ON ==
t=0 L TOOK the lock
t=1 H WANTS the lock
t=4 L RELEASING the lock
t=4 H GOT the lock
t=4 M starts burning CPU
t=7 M done
== priority inheritance OFF ==
t=0 L TOOK the lock
t=1 H WANTS the lock
t=2 M starts burning CPU
t=5 M done
t=7 L RELEASING the lock
t=7 H GOT the lock
- Cooperative core: task control block, context switch, round-robin, simulated clock, sleep
- Preemption and fixed-priority scheduling
- Mutex, semaphore, priority inversion demo and priority inheritance fix
- Pool allocator, benchmarks, design write-up
- STM32 port (SysTick, PendSV, MSP/PSP)
- On-hardware latency measurements and demo
Measured on Linux (x86_64, pinned to Core 0) across 8,000,000 samples (40 runs × 200,000 iterations):
| Benchmark | Min | p50 (Median) | p99 | p99.9 | Worst Max |
|---|---|---|---|---|---|
| Raw Context Switch (1-way) | 145 ns | 162 ns | 261 ns | 928 ns | 1.15 ms |
yield() Round Trip |
283 ns | 315 ns | 444 ns | 1.47 µs | 684 µs |
Full methodology, baseline comparisons, and analysis are published in docs/benchmarks.md.
Swastik Bose, a.k.a VasuBhakt