Rivet RTOS — zero-allocation, dual-tier RTOS for microcontrollers.
Architecture
Two tiers of concurrency, unified under one priority scheduler:
- Preemptive tier (
#[rivet::ptask]/ [spawn_ptask!]): each task gets its own stack. The timer tick can suspend a running task at any point (not just at a yield/await) and resume a higher-priority one instead — real priority preemption, with priority inheritance on [preempt::PriorityMutex] to avoid priority inversion. - Cooperative tier (
#[rivet::task]):async fntasks compiled toFuturestate machines, polled on a single shared stack — zero per-task stack cost, ideal for I/O-bound/event-driven logic. This tier runs as an ordinary preemptive task at the lowest priority, so any real preemptive task immediately preempts it; it fills otherwise idle CPU time and only callsWFIwhen nothing anywhere is ready.
Targets
- ARM Cortex-M (M0+/M3/M4/M7/M33) — via the
arch-cortex-mfeature - RISC-V (RV32) — via the
arch-riscvfeature
Example
use rivet::sync::Semaphore;
static SEM: Semaphore<1> = Semaphore::new(0);
// Cooperative: fine for I/O-bound logic.
#[rivet::task(priority = 0)]
async fn background() {
loop {
SEM.acquire().await;
}
}
// Preemptive: genuinely can't be starved by a lower/equal priority
// task that never yields.
static CFG: u32 = 42;
fn critical_task(cfg: &'static u32) -> ! {
loop {
// real work, no .await required anywhere
}
}
fn main() -> ! {
rivet::init();
rivet::spawn_ptask!(stack = 2048, priority = 5, entry = critical_task, arg = CFG);
rivet::run();
}