12 KiB
12 KiB
分区 RTOS:INTEGRITY / ARINC 653 / VxWorks 653 / PikeOS
这类系统的调度**不止一层**:分区级调度(major frame / partition window / budget)
↓
分区内调度(进程/任务优先级,本分区自己的调度器)
于是最常见的误判是:
Task A priority = 250,Task B = 100
B 在跑,A 完全没运行
→ 不是"调度器坏了",也不是 starvation
→ A 可能处在当前没有执行窗口/预算的分区里
"高优先级线程没运行"在这里首先是分区级的解释,然后才是任务级的解释。 </CORE RULE>
一、两层调度与 major frame
- 分区级:固定、循环、离线定义的调度。分区在一个循环区间内被周期性释放一段时间
- 这个区间叫 major time frame(MAF),由若干 partition window 组成;每个窗口由时长、偏移、周期性定义
- 激活顺序在配置表里静态定义,运行期不可更改;设计良好时 MAF 时长 ≈ 各分区周期的最小公倍数
- 分区调度表列出相对 MAF 起点的抢占点;调度就是"当前时钟落在某分区的窗口内(偏移 → 偏移+时长)"
- 分区内:由分区自己的调度器管理其进程(ARINC 653 语境下通常是固定优先级抢占式)
分析要求:时间线必须先在分区级对齐,再谈线程级。
二、分区模式:进程"不跑"常常是还没进 NORMAL
ARINC 653 的分区有四态:IDLE / COLD_START / WARM_START / NORMAL
| 模式 | 含义 |
|---|---|
| COLD_START | 初始化进行中;抢占被锁定;应用在跑初始化代码;初始环境可能需要从非易失存储器把代码拷到 RAM |
| WARM_START | 也是初始化且抢占锁定,但初始环境与冷启动可以不同(例如不需要从 NVM 拷代码) |
| NORMAL | 初始化完成,分区的进程调度器活跃,已创建的就绪进程可以运行 |
| IDLE | 没有进程在执行,但分配给该分区的窗口仍保留 |
- 迁移关系:IDLE → COLD/WARM_START;COLD_START → NORMAL;NORMAL → COLD/WARM_START(重启);→ IDLE(关机/设为 IDLE)
- 服务:
SET_PARTITION_MODE与GET_PARTITION_STATUS(返回标识、周期、时长、锁层级、运行模式、启动条件) - 初始化模式(COLD/WARM_START)下只有主进程可调度;错误处理程序在初始化阶段创建,并可调用
SET_PARTITION_MODE重启分区
所以:
CREATE_PROCESS() / START() 都做了,但进程一直不跑
→ 先查是否执行了 SET_PARTITION_MODE(NORMAL)
→ 而不是立即判调度器损坏
三、采样端口与队列端口:语义不同,不能混
| 采样端口(sampling) | 队列端口(queuing) | |
|---|---|---|
| 缓冲 | 单条消息 | 可配置的消息条数 |
| 覆盖 | 新消息覆盖旧消息,应用总是读到最新的 | 不覆盖,按 FIFO 传送 |
| 丢消息 | 可能丢/被覆盖 | 不丢;队列满时发送失败/阻塞 |
| 刷新周期 | 只对采样模式的接收有意义(判断是否有新消息到达) | 不适用 |
- channel 把一个源端口连到一个或多个目的端口;分区之间由内核强制内存保护,其他分区无法访问本分区的端口
所以:
连续写了 A B C,最后只读到 C
→ 对采样端口可能完全正常
→ 对队列端口则不正常
四、INTEGRITY:空间 + 时间 + 资源三域分区
- 微内核架构,支持多个受保护的虚拟地址空间,每个可含多个应用任务;用硬件 MMU 建立隔离
- 完整的分区包含空间、时间与资源三个域;失败不会跨分区传播
- 固定预算:可为每个进程分配固定的 CPU 时间与内存预算;保证时间窗也意味着运行中的任务不会超出其窗口
- 其他机制:实时调度器支持多优先级与完整的 CPU 百分比分配控制;内核服务时间有界;内核空间不做动态内存分配;内置 ARINC 653 Part 1 分区调度器(带保证的执行时间窗);内存配额系统防止一个地址空间耗尽另一个的内存;内核内存不用于消息、信号量等由进程请求创建的对象
- 静态配置:架构师预先写好静态配置文件,定义分区、任务集、内存对象、链接、连接通道、时钟与分区调度机制;启动表定义归属;连接静态分配且不可绕过;MMU 设置可静态验证
- 多核:不同分区时间窗内可绑定到不同核;共享资源争用可使 WCET 增加 8–13 倍(这也是相关适航指导强调的)
RE 主线:
CPU 明明还有空闲,应用却拿不到更多执行时间
→ 可能是预算隔离(设计如此),不是调度效率 bug
五、PikeOS:还有第三层
PikeOS 是第二代分离微内核(同时是 hypervisor):静态循环调度分区(时间隔离)+ 内存区(空间隔离);每个分区有自己的调度结构,支持 256 个优先级;系统分区与当前活动分区同时被调度以提供系统服务。
POSIX guest 的层次:
PikeOS 分区/资源调度器
↓
PikeOS system thread(每核一个可供该 POSIX 内核使用)
↓
POSIX guest 内核自己的调度器
↓
POSIX 用户线程
- POSIX 内核自己的调度器把它的用户线程映射到一个 PikeOS system thread;许多 POSIX 驱动还会自建 I/O 线程
- POSIX guest 实现的是 PSE52 子集,加上实时与 PikeOS 专有扩展(包含 ARINC 653 采样/队列端口)
- APEX guest:完整实现 ARINC 653 P1-5 与部分 P2-4(分区管理、健康监控、采样/队列端口、进程管理、分区内通信与同步、logbook、文件系统、内存块、服务访问点端口)
- APEX 服务经一张链接在固定地址的 API table 进入:开发时应用与库及链接脚本给出的 API 服务表地址链接
- 初始化完成后 APEX 内核把控制交给用户提供的
MAIN(),起始于 COLD_START(抢占锁定、创建静态资源),之后分区转入 NORMAL(进程调度器活跃、完整 APEX API 可用)
两条推论:
guest 内线程是最高优先级,但延迟突然到 10 ms
→ 不能只看 pthread 调度器:查当前分区是否有执行窗口、
对应 system thread 是否可运行、CPU affinity/分区调度是什么
看到大量 ldr x16, [固定基址+偏移]; blr x16
→ 先查是否是 APEX 服务表,而不是控制流混淆
六、Deos:两级调度 + slack + SafeMC
- 时间/空间/资源分区的安全关键 RTOS(DAL A 认证):分区允许把不同设计保证等级的软件混跑在同一处理器上,并提供故障隔离与应用重启
- 两级调度模型(SafeMC 明确描述):
Level 1:时间被划分为在各核之间【对齐】的执行窗口
Level 2:每个核/window 指派具体 scheduler
├─ ARINC 653
├─ Deos RMA(速率单调)
└─ POSIX
应用被指派给一个或多个 scheduler;每个 scheduler 可跨多个 process/partition 调度多个 task
- 同一颗核在不同时间段可以跑不同调度规律(window 1 用 ARINC 653、window 2 用 POSIX、window 3 用 RMA 是这套架构能表达的)——trace 里调度规律切换不能自动判调度器状态损坏
- Slack Scheduling(滑动时间窗):窗口可以压缩、扩张、滑动——分区提前完成可压缩窗口,需要更多时间且有空闲可扩张,也可以让他人提前或延后开始。所以"budget 给了 10 ms、任务只用了 6 ms,另一个任务拿到剩余 CPU"不是时间分区逃逸,而是 slack 回收;CPU 接近 100% 也可以仍在预算内
- Cache partitioning:软件实现、可配置,把缓存隔离做到应用/分区级(不只是核级),免去分区切换时的 cache flush(那会影响 WCET),并与**内存池(memory pooling)**互补(控制应用落在物理内存的哪里)
- 开发工具本身也可能利用 slack time 做通信/profiling/monitoring 以少干扰关键负载——trace 里"应用执行 → 一小段工具流量 → 应用执行"先确认是不是这个
- 多核用 BMP(SMP 的扩展)+ 安全调度 + 缓存分区 + 内存池 限制共享资源干扰。任务 READY、CPU 也有,但执行被多核策略约束,不一定是普通调度决策——要恢复 core assignment / window / cache partition / memory pool / 跨核干扰策略
- 也可以承载其他环境:例如某 para-virtualized RTOS 实现运行在它的安全分区里,对外提供 POSIX 接口——看到
pthread_*不代表脱离了 Deos 分区控制 - 两个不同安全分区能看到共享内存也不等于隔离被破坏:应查是否配置为共享、权限、谁可写、生命周期
- 若观测到 major frame 起点缓慢漂移:Deos 提供外部时钟同步类能力(本次核验未直接命中上游资料,作为候选解释之一并在具体型号文档上确认),不要直接判 timer drift 或 trace 时钟坏了
排错顺序(重要):
Task 没运行
→ 属于哪个 process/partition?
→ 在哪个 core?
→ 当前 window 是否 active?
→ window 内是什么 scheduler?
→ 本地优先级/状态?
→ budget?
→ SafeMC 限制?
→ 才看 deadlock/bug
对这类系统,配置与分区调度表优先于反汇编猜内部调度器——公开文档未必开放全部内核细节。
同族系统
- XtratuM(配置驱动的分离 hypervisor):同样是"静态配置 + major frame + 时间槽",另有固定优先级计划与多计划切换,见 re-hypervisor/xtratum
- LynxSecure(静态分离内核):见 re-hypervisor/lynxsecure
- Quest-V(多内核 sandbox + 每 sandbox 一个 monitor):见 re-hypervisor/questv
- Jailhouse / Bao(静态分区 hypervisor):见 re-hypervisor/jailhouse、re-hypervisor/bao
决策树
拿到分区 RTOS 目标
├─ 先分层:分区级调度 vs 分区内调度
│ ├─ 对齐 major frame / partition window(时长、偏移、周期)
│ └─ 再谈进程/任务优先级
├─ 高优先级线程不运行
│ ├─ 查它所属分区当前是否有执行窗口
│ ├─ 查分区模式(是否还在 COLD/WARM_START,未进 NORMAL)
│ └─ 查资源/时间预算是否已耗尽(故意的隔离)
├─ 通信异常
│ ├─ 采样端口:覆盖语义,"只读到最新"属正常
│ └─ 队列端口:FIFO、不覆盖,满则失败/阻塞
├─ 看到固定地址函数表
│ └─ 先考虑 APEX 服务表一类的 ABI,不要直接判混淆
└─ 多核 / 性能归因
└─ 把共享资源争用与预算隔离算进去(WCET 可能显著放大)
工具与验证
- 调度:分区调度表 / 时间窗配置、MAF 与窗口参数、分区模式状态
- 资源:分区/进程的 CPU 时间与内存配额、静态配置文件与启动表
- 通信:端口类型(采样/队列)与各自参数
- 验证:能同时说清「分区级时间窗 + 分区内调度结果 + 预算/模式状态」,三者缺一不能解释"为什么没跑"
该平台的坑(汇总)
- 用统一的优先级队列解释调度:至少两层(PikeOS 场景是三层)
- 把"高优先级线程不跑"当 starvation 或调度器 bug:先看分区窗口与预算
- 忽略分区模式:COLD/WARM_START 下只有主进程可调度,进程当然"不跑"
- 把采样端口当队列端口:覆盖语义下"只读到最新"是正常的
- 把队列端口当采样端口:消息不会互相覆盖,丢失就一定是问题
- 把资源/时间预算隔离当性能缺陷:固定预算是隔离机制的一部分
- 只逆 guest 内容:PikeOS 一类系统里 guest 调度器不是最终调度器
- 把固定地址的 APEX 服务表当控制流混淆
- 多核分析忽略共享资源争用:WCET 可能成倍放大