可移植多任务调度内核,用于嵌入式环境,与应用程序一起编译打包,参考 FreeRTOS 实现。
- 软件还在开发中,API 也相当原始且不稳定
- 关于工作原理,代码(包括汇编)中有详细说明,请先阅读
- 单物理线程任务优先级+时间片调度机制,高优先级抢占,同优先级公平调度
- 堆内存分配器
- 二值信号量、计数信号量、信号广播、互斥锁、任务通知
- 多生产者多消费者队列
- 临界段
- 栈溢出检查
- PubSub 模式消息总线
- 软件定时器
- 驱动抽象层:
Device顶层抽象 + 五能力 trait(流/块/控制/总线/事件),注册表与编译期清单只认&'static dyn Device,"名字就是总线" - 基于 FatFS 文件系统
- 基于 smoltcp 网络协议栈
- 宿主回归:
cargo test --lib默认 features 实测 80 passed;门禁全特征组合(见ci/gate.sh,含 fs/net/usb/ble)实测 159 passed(2026-09-03,rustc 1.97;旧计数 148 已按实测修正,历史见 issue #11;计数随新增测试浮动,以ci/gate.sh实测为准) - QEMU 执行级:
ci/gate.sh在 virt 机真跑内核——qemu_pingpong200 轮乒乓 +qemu_kernel_tests24 项全内核机制自测(抢占/时间片/阻塞类 IPC/定时器/时基/堆/总线/任务回收/可重入锁/优先级继承/完整 PI 多锁/PCP 天花板阻塞/PI 交叉持锁死锁确认/TLSF 碎片共限/TLSF 分配确定性/tickless 错峰唤醒/远期期限单次到点/UART RX 外部中断冻眠唤醒/早醒弹墙钟拍账/噪声风暴停留 idle 不漂移),全绿自退出;另有 tlsf 全局后端门禁(24/24 不变 = 分配器换引擎对内核透明)与qemu_smp9 项多核调度门禁 - 真机验证:gd32vf103 已验;f4/f1 常数、h7 时序、cm32m4、rp2040、ch32 系、esp32c3 待上板
- RISCV
- GD32VF103xx
- qemu_riscv: QEMU virt 机(标准 CLINT+NS16550;执行级验证 2026-08-24——15 项自测 ×10 连稳定,2026-08-26 扩至 23 项(新增 PCP 天花板阻塞、PI 交叉持锁死锁确认、TLSF 碎片共限、TLSF 分配确定性、tickless 错峰唤醒、远期期限单次到点、UART RX 外部中断冻眠唤醒 + 早醒弹墙钟拍账——ch29 章末练习 1 兑现,stdin 喂字节握手),2026-09-02 扩至 24 项(噪声风暴停留 idle 不漂移——tickless 踩坑 5 下半场专项守卫);SMP 多核执行验证 2026-08-26——
smp::enable()显式开启,从核参与调度,qemu_smp 9 项在 -smp 2/3/4/8 全绿;TaskBuilder::affinity绑核确定性放置) - CM32M4xxR(RISC-V/N308;构建级验证 2026-08-23,真机待验)
- ESP32C3: esp32c3(PAC 直依赖;构建级验证 2026-08-23,真机待验——启动需 direct boot/镜像头)
- CH32V3: ch32v307(QingKe V4F;构建级验证 2026-08-23,真机待验)
- CH32V2: ch32v203(QingKe V4B;构建级验证 2026-08-23,真机待验)
- CH32V1: ch32v103(QingKe V3A;构建级验证 2026-08-23,真机待验)
- CM7F
- STM32H7B0VBT6
- CM4F
- STM32F401CCU6
- STM32F427VIT6
- STM32F411CEU6
- CM3
- STM32F103C8T6
- CM0+
- RP2040(rp2040-hal 0.9;构建级验证 2026-08-23,真机待验)
- CR5F
- qemu_arm_r52: QEMU xlnx-zcu102 的 Cortex-R5F(armv7r-none-eabi;执行级验证 2026-08-30——200 轮乒乓 + tick 心跳 + VFP 帧 100 轮跨切换保持,补丁版 QEMU 跑通;CI 执行级门禁
.github/workflows/r52.yml——补丁版 QEMU 构建 + 双例程断言全绿;无 PendSV 架构的「中断借道 + 调度循环」移植,方法论见书稿第 31/32 章;真机待验)
- qemu_arm_r52: QEMU xlnx-zcu102 的 Cortex-R5F(armv7r-none-eabi;执行级验证 2026-08-30——200 轮乒乓 + tick 心跳 + VFP 帧 100 轮跨切换保持,补丁版 QEMU 跑通;CI 执行级门禁
- 通道 A · 本机一条命令(首次自动下载静态 QEMU 到
.tools/,约 90MB):bash ci/gate.sh # host 回归 + 示例链接 + QEMU 执行级(24/24 等) - 通道 B · GitHub Codespaces:仓库根有
.devcontainer.json,云端打开即跑,本机什么都不装 - 通道 C · 只看结果:每次 push 的 CI 门禁(含 QEMU 执行级)全绿记录:
- 只想跑 host 单测(不需要 QEMU):注意仓库
.cargo/config.toml默认thumbv7emtarget, 请显式指定宿主或先rustup target add thumbv7em-none-eabihf:cargo test --lib --target "$(rustc -vV | sed -n 's/^host: //p')"
没有开发板也能跑:QEMU 执行级验证不需要任何硬件(安装 QEMU 后)
cargo build --example qemu_kernel_tests --features qemu_riscv,timer --target riscv32imac-unknown-none-elf --release
# 测试 22/23(冻眠唤醒/早醒拍账)需经 qemu stdin 喂字节——内核打
# 握手标记、主机读到才写(ci/feed_qemu.py,时序零假设):
python ci/feed_qemu.py 180 qemu-system-riscv32 \
target/riscv32imac-unknown-none-elf/release/examples/qemu_kernel_tests
# 期望输出 24/24 passed,进程以退出码 0 自行结束
# 全局分配器换引擎(tlsf feature:整个内核的堆分配走手写迷你 TLSF):
cargo build --example qemu_kernel_tests --features qemu_riscv,timer,tlsf --target riscv32imac-unknown-none-elf --release
# 同上用 feed_qemu.py 跑,期望仍是 24/24 passed——分配器后端对内核透明(第 28 章)
# SMP 多核执行验证(应用 smp::enable() 后从核参与调度):
cargo build --example qemu_smp --features qemu_riscv,timer --target riscv32imac-unknown-none-elf --release
qemu-system-riscv32 -M virt -smp 2 -nographic -bios none -kernel \
target/riscv32imac-unknown-none-elf/release/examples/qemu_smp
# 期望输出 smp PASS: 9/9(双核并行/跨核唤醒/锁与堆压力/节拍推进/绑核放置/定时器跨核/每核 runqueue 负载均衡)
# 同一 ELF 支持 -smp 2..8(核数梯度回归:-smp 2/3/4/8 全绿)如果您有一块 longan-nano 或者 stm32f401ccu6 或者 stm32f103c8t6 最小系统板,那么example中的例子直接可以跑起来
-
打开一个终端
- cd debug/gd32vf103
- ./openocd.sh
-
串口调试
- 把调试器插到 usb 口
- window 平台需要你找一款串口助手连接串口即可
- linux 或者 mac 平台执行 screen /dev/$串口设备 57600
-
打开另外一个终端
-
gd32vf103: --target riscv32imac-unknown-none-elf
-
stm32f4: --target thumbv7em-none-eabihf
-
stm32f1: --target thumbv7m-none-eabi
-
rp2040: --target thumbv6m-none-eabi(rp2040-hal 0.9 复活;构建级验证 2026-08-23,真机待验)
-
qemu_riscv: QEMU virt 机(标准 CLINT+NS16550;执行级验证——见上文"验证体系")
-
信号广播示例
- cargo run --example broadcast --features=gd32vf103 --target riscv32imac-unknown-none-elf --release
-
LED 示例,三个任务分别控制三色 LED
- cargo run --example led --features=gd32vf103 --target riscv32imac-unknown-none-elf --release
-
多任务切换示例,5 个任务,4 个任务循环一段时间后退出
- cargo run --example multitask --features=gd32vf103 --target riscv32imac-unknown-none-elf --release
-
通知示例,一个通知另外一个
- cargo run --example notify --features=gd32vf103 --target riscv32imac-unknown-none-elf --release
-
队列示例,两个发,三个收消息
- cargo run --example queue --features=gd32vf103 --target riscv32imac-unknown-none-elf --release
-
信号量示例,两个发,三个收
- cargo run --example semaphore --features=gd32vf103 --target riscv32imac-unknown-none-elf --release
-
消息服务总线示例,
- cargo run --example evbus --features=gd32vf103 --target riscv32imac-unknown-none-elf --release
-
软件定时器
- cargo run --example timer --features=gd32vf103,timer --target riscv32imac-unknown-none-elf --release
-
-
如果您能在终端看到任务工作时的日志输出,恭喜您已经成功了
/// 移植层接口定义
pub trait Portable {
/// 完全内存屏障
/// 保证在屏障之前的任何存储操作先于屏障之后的代码执行。
fn barrier();
/// 临界区保护函数
fn free<F, R>(f: F) -> R
where
F: FnOnce(&CriticalSection) -> R;
/// 开全局中断
fn enable_interrupt();
/// 关全局中断
fn disable_interrupt();
/// 启动调度器
fn start_scheduler() -> !;
/// 软中断
fn irq();
/// 关闭软中断
fn disable_irq();
/// 获取systick
fn systick() -> u64;
/// 硬件延时,单位us
fn delay_us(us: u64);
/// 保存任务环境到任务栈
fn save_context(task: &mut Task);
// ---- SMP 扩展面(第 25 章改造路线②③,全部带单核默认实现)----
/// 当前核(hart)ID——SMP 口按 mhartid;单核口恒 0(默认)
fn hart_id() -> u16 {
0
}
/// 参与调度的物理核数——单核恒 1(默认)
fn core_count() -> u16 {
1
}
/// 向指定核发软中断(IPI)——默认退化为本核 irq();SMP 口按目标核寻址
fn irq_to(hart: u16) {
let _ = hart;
Self::irq();
}
/// 启动从核参与调度——单核默认空操作;多核口唤醒停泊的从核
fn start_secondary_cores() {}
}- 本仓库代码遵循 MIT 协议(见 LICENSE),可自由使用、修改、商用,请保留版权声明。
- 作者正在撰写基于本仓库的专著《用 Rust 手写 RTOS 内核》(书稿文字独立于 MIT 授权,未经许可不得复制/出版)。
- 若你计划基于本仓库编写书籍、教程、课程或深度文章:欢迎先通过 GitHub Issue / Discussions 联系作者,可提供内容审阅与联合署名,避免与在写专著内容冲突。

