#thread #linux

linux-rtic

Linux 系统下的实时中断驱动的并发 (RTIC) 实现

2 个版本

0.1.1 2021 年 10 月 15 日
0.1.0 2021 年 10 月 12 日

#1016并发

Apache-2.0 OR MIT

23KB
242

linux-rtic

License Cargo Documentation

针对实时 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