2 个版本
0.1.1 | 2021 年 10 月 15 日 |
---|---|
0.1.0 | 2021 年 10 月 12 日 |
#1016 在 并发 中
23KB
242 行
linux-rtic
针对实时 Linux 的 RTIC 实现。
工作原理
此 RTIC 实现基于通过为每个任务优先级组启动一个线程的 std::thread
。线程使用 SCHED_FIFO
实时策略进行初始化。任务优先级与 Linux 优先级一一对应,通常范围在 1-99 之间。
调度
任务调度通过 futex-queue 完成,它巧妙地利用 futex 系统调用在单个系统调用上等待立即和计划(定时)任务。不需要定时器线程(以及额外的上下文切换)。
资源锁定
原始的 cortex-m-rtic 使用堆栈资源策略 (SRP),但在用户空间 Linux 中难以模拟。首先,设置每个锁/解锁的线程优先级涉及昂贵的系统调用(在树莓派 4 上约为 10us)。其次,设置线程优先级并不能保证低优先级线程不会运行。低优先级线程可能运行在不同的核心上,或者当高优先级线程挂起时(即 I/O 系统调用)。虽然可以通过备份同步机制(互斥锁)修复内存安全问题,但对于实时应用程序来说,系统调用开销太高。
为了解决这个问题,编写了一个 pcp-mutex 库,它实现了原始优先级上限协议 (OPCP)。这允许保留 SRP 的两个重要属性:限制优先级反转和静态预防死锁。此互斥锁在快速路径上是无锁的。技术细节请参阅 pcp-mutex 的 README。
其他说明
由于上下文切换开销(在树莓派 4 上约为 10us)和其它方法已被探索,因此在用户空间线程中调度任务较慢。
- 较老的 linux-rtfm 实现使用 POSIX 信号。它们比线程上下文切换更快,但是任务仅限于可重入(信号安全)函数,这迫使用户使用
no_std
。此外,由于信号屏蔽系统调用,资源锁定较慢。 - 内核线程仅略快,因为大部分开销似乎都在调度程序本身。因此,放弃用户空间安全性和 std 库似乎不值得。
- 硬中断上下文将最接近 cortex-m-rtic 所做的,但 Linux 不支持中断优先级(只有 IRQ 线程有优先级),并且需要重大的内核修改。
示例
运行示例需要 Linux 系统具有预emption-RT 补丁的内核,以支持 SCHED_FIFO
,并且需要 root 权限。通过使用 --no-default-features
编译可以取消这个要求,但这样所有任务将共享相同的优先级。
构建
构建 cargo --release --example priority_inversion
运行(需要sudo权限以执行 sched_setscheduler
系统调用)
sudo target/release/examples/priority_inversion
单核
sudo taskset -c 1 target/release/examples/priority_inversion
没有实时优先级
cargo run --release --example priority_inversion --no-default-features
使实时更加真实的技巧
- 应用
PREEMPT-RT
内核补丁,并用CONFIG_PREEMPT_RT_FULL
编译内核以减少内核中的不可抢占部分。 - 禁用动态CPU频率缩放。可以在内核配置中或使用
cpufreq-set -g performance
来实现。 - 使用
isolcpus
内核参数在独立核心上运行 RTIC。 - 确保外围进程(例如
spi0
)以实时优先级调度:sudo chrt -f -p 50 $(pidof spi0)
. - 尝试限制不同优先级任务之间的调度,以减少上下文切换开销。
- 观看 编写 Linux 实时应用的检查清单 - John Ogness, Linutronix GmbH
致谢
这项工作是我荷兰特温特大学论文的一部分。
依赖项
~5–13MB
~158K SLoC